diff options
author | dfr <dfr@FreeBSD.org> | 1998-06-10 19:59:41 +0000 |
---|---|---|
committer | dfr <dfr@FreeBSD.org> | 1998-06-10 19:59:41 +0000 |
commit | 8bc7b7e51ae3716868e58674256cc4a2c26d83b0 (patch) | |
tree | 21a6551c231fbf12d3fd289ce8465fe1645ddfb0 | |
parent | a3798e908e88069196210234df0ec415265a2b2a (diff) | |
download | FreeBSD-src-8bc7b7e51ae3716868e58674256cc4a2c26d83b0.zip FreeBSD-src-8bc7b7e51ae3716868e58674256cc4a2c26d83b0.tar.gz |
Add missing copyrights. Thanks to Jason Thorpe for politely noting the
mistake...
-rw-r--r-- | sys/alpha/alpha/locore.s | 297 | ||||
-rw-r--r-- | sys/alpha/alpha/vm_machdep.c | 516 | ||||
-rw-r--r-- | sys/powerpc/aim/vm_machdep.c | 516 | ||||
-rw-r--r-- | sys/powerpc/powerpc/vm_machdep.c | 516 |
4 files changed, 1845 insertions, 0 deletions
diff --git a/sys/alpha/alpha/locore.s b/sys/alpha/alpha/locore.s new file mode 100644 index 0000000..48f78c3 --- /dev/null +++ b/sys/alpha/alpha/locore.s @@ -0,0 +1,297 @@ +/*- + * Copyright (c) 1998 Doug Rabson + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $Id: locore.s,v 1.1 1998/06/10 10:52:50 dfr Exp $ + */ +/* + * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Chris G. Demetriou + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <machine/asm.h> +#include <sys/syscall.h> +#include <assym.s> + +/* + * PTmap is recursive pagemap at top of virtual address space. + * Within PTmap, the lev1 and lev0 page tables can be found. + */ + .globl PTmap,PTlev2,PTlev1,PTlev1pte + .equ PTmap,VPTBASE + .equ PTlev2,PTmap + (PTLEV1I << ALPHA_L2SHIFT) + .equ PTlev1,PTlev2 + (PTLEV1I << ALPHA_L3SHIFT) + .equ PTlev1pte,PTlev1 + (PTLEV1I * PTESIZE) + +/* + * Perform actions necessary to switch to a new context. The + * hwpcb should be in a0. + */ +#define SWITCH_CONTEXT \ + /* Make a note of the context we're running on. */ \ + stq a0, curpcb ; \ + \ + /* Swap in the new context. */ \ + call_pal PAL_OSF1_swpctx + + .text + EXPORT(kernel_text) +kernel_text: + + NESTED(locorestart, 1, 0, ra, 0, 0) + + br pv,1f +1: LDGP(pv) + + /* Load KGP with current GP. */ + or a0,zero,s0 /* save pfn */ + or gp,zero,a0 + call_pal PAL_OSF1_wrkgp /* clobbers a0, t0, t8-t11 */ + or s0,zero,a0 /* restore pfn */ + + /* + * Call alpha_init() to do pre-main initialization. + * alpha_init() gets the arguments we were called with, + * which are already in a0, a1, a2, a3, and a4. + */ + CALL(alpha_init) + + /* Set up the virtual page table pointer. */ + ldiq a0, VPTBASE + call_pal PAL_OSF1_wrvptptr /* clobbers a0, t0, t8-t11 */ + + /* + * Switch to proc0's PCB, which is at U_PCB off of proc0paddr. + */ + lda t0,proc0 /* get phys addr of pcb */ + ldq a0,P_MD_PCBPADDR(t0) + SWITCH_CONTEXT + + /* + * We've switched to a new page table base, so invalidate the TLB + * and I-stream. This happens automatically everywhere but here. + */ + ldiq a0, -2 /* TBIA */ + call_pal PAL_OSF1_tbi + call_pal PAL_imb + + /* + * Construct a fake trap frame, so execve() can work normally. + * Note that setregs() is responsible for setting its contents + * to 'reasonable' values. + */ + lda sp,-(FRAME_SIZE * 8)(sp) /* space for struct trapframe */ + mov sp, a0 /* main()'s arg is frame ptr */ + CALL(main) /* go to main()! */ + + /* + * Call exception_return, to simulate return from (fake) + * exception to user-land, running process 1, init! + */ + jmp zero, exception_return /* "And that's all she wrote." */ + END(locorestart) + + +/**************************************************************************/ + +/* + * Signal "trampoline" code. Invoked from RTE setup by sendsig(). + * + * On entry, stack & registers look like: + * + * a0 signal number + * a1 signal specific code + * a2 pointer to signal context frame (scp) + * a3 address of handler + * sp+0 saved hardware state + * . + * . + * scp+0 beginning of signal context frame + */ + +NESTED(sigcode,0,0,ra,0,0) + lda sp, -16(sp) /* save the sigcontext pointer */ + stq a2, 0(sp) + jsr ra, (t12) /* call the signal handler (t12==pv) */ + ldq a0, 0(sp) /* get the sigcontext pointer */ + lda sp, 16(sp) + CALLSYS_NOERROR(sigreturn) /* and call sigreturn() with it. */ + mov v0, a0 /* if that failed, get error code */ + CALLSYS_NOERROR(exit) /* and call exit() with it. */ +XNESTED(esigcode,0) + END(sigcode) + + .data + EXPORT(szsigcode) + .quad esigcode-sigcode + .text + +/**************************************************************************/ + +/* + * savefpstate: Save a process's floating point state. + * + * Arguments: + * a0 'struct fpstate *' to save into + */ + +LEAF(savefpstate, 1) + LDGP(pv) + /* save all of the FP registers */ + lda t1, FPREG_FPR_REGS(a0) /* get address of FP reg. save area */ + stt $f0, (0 * 8)(t1) /* save first register, using hw name */ + stt $f1, (1 * 8)(t1) /* etc. */ + stt $f2, (2 * 8)(t1) + stt $f3, (3 * 8)(t1) + stt $f4, (4 * 8)(t1) + stt $f5, (5 * 8)(t1) + stt $f6, (6 * 8)(t1) + stt $f7, (7 * 8)(t1) + stt $f8, (8 * 8)(t1) + stt $f9, (9 * 8)(t1) + stt $f10, (10 * 8)(t1) + stt $f11, (11 * 8)(t1) + stt $f12, (12 * 8)(t1) + stt $f13, (13 * 8)(t1) + stt $f14, (14 * 8)(t1) + stt $f15, (15 * 8)(t1) + stt $f16, (16 * 8)(t1) + stt $f17, (17 * 8)(t1) + stt $f18, (18 * 8)(t1) + stt $f19, (19 * 8)(t1) + stt $f20, (20 * 8)(t1) + stt $f21, (21 * 8)(t1) + stt $f22, (22 * 8)(t1) + stt $f23, (23 * 8)(t1) + stt $f24, (24 * 8)(t1) + stt $f25, (25 * 8)(t1) + stt $f26, (26 * 8)(t1) + stt $f27, (27 * 8)(t1) + .set noat + stt $f28, (28 * 8)(t1) + .set at + stt $f29, (29 * 8)(t1) + stt $f30, (30 * 8)(t1) + + /* + * Then save the FPCR; note that the necessary 'trapb's are taken + * care of on kernel entry and exit. + */ + mf_fpcr ft0 + stt ft0, FPREG_FPR_CR(a0) /* store to FPCR save area */ + + RET + END(savefpstate) + +/**************************************************************************/ + +/* + * restorefpstate: Restore a process's floating point state. + * + * Arguments: + * a0 'struct fpstate *' to restore from + */ + +LEAF(restorefpstate, 1) + LDGP(pv) + /* + * Restore the FPCR; note that the necessary 'trapb's are taken care of + * on kernel entry and exit. + */ + ldt ft0, FPREG_FPR_CR(a0) /* load from FPCR save area */ + mt_fpcr ft0 + + /* Restore all of the FP registers. */ + lda t1, FPREG_FPR_REGS(a0) /* get address of FP reg. save area */ + ldt $f0, (0 * 8)(t1) /* restore first reg., using hw name */ + ldt $f1, (1 * 8)(t1) /* etc. */ + ldt $f2, (2 * 8)(t1) + ldt $f3, (3 * 8)(t1) + ldt $f4, (4 * 8)(t1) + ldt $f5, (5 * 8)(t1) + ldt $f6, (6 * 8)(t1) + ldt $f7, (7 * 8)(t1) + ldt $f8, (8 * 8)(t1) + ldt $f9, (9 * 8)(t1) + ldt $f10, (10 * 8)(t1) + ldt $f11, (11 * 8)(t1) + ldt $f12, (12 * 8)(t1) + ldt $f13, (13 * 8)(t1) + ldt $f14, (14 * 8)(t1) + ldt $f15, (15 * 8)(t1) + ldt $f16, (16 * 8)(t1) + ldt $f17, (17 * 8)(t1) + ldt $f18, (18 * 8)(t1) + ldt $f19, (19 * 8)(t1) + ldt $f20, (20 * 8)(t1) + ldt $f21, (21 * 8)(t1) + ldt $f22, (22 * 8)(t1) + ldt $f23, (23 * 8)(t1) + ldt $f24, (24 * 8)(t1) + ldt $f25, (25 * 8)(t1) + ldt $f26, (26 * 8)(t1) + ldt $f27, (27 * 8)(t1) + ldt $f28, (28 * 8)(t1) + ldt $f29, (29 * 8)(t1) + ldt $f30, (30 * 8)(t1) + + RET + END(restorefpstate) + +/* + * When starting init, call this to configure the process for user + * mode. This will be inherited by other processes. + */ + LEAF_NOPROFILE(prepare_usermode, 0) + RET + END(prepare_usermode) + + .data + EXPORT(proc0paddr) + .quad 0 + + .text + diff --git a/sys/alpha/alpha/vm_machdep.c b/sys/alpha/alpha/vm_machdep.c new file mode 100644 index 0000000..89edb49 --- /dev/null +++ b/sys/alpha/alpha/vm_machdep.c @@ -0,0 +1,516 @@ +/*- + * Copyright (c) 1982, 1986 The Regents of the University of California. + * Copyright (c) 1989, 1990 William Jolitz + * Copyright (c) 1994 John Dyson + * 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, and 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. + * + * from: @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91 + * Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$ + * $Id: vm_machdep.c,v 1.1 1998/06/10 10:53:40 dfr Exp $ + */ +/* + * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Chris G. Demetriou + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/buf.h> +#include <sys/vnode.h> +#include <sys/vmmeter.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> + +#include <machine/clock.h> +#include <machine/cpu.h> +#include <machine/md_var.h> +#include <machine/prom.h> + +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <vm/vm_prot.h> +#include <sys/lock.h> +#include <vm/vm_kern.h> +#include <vm/vm_page.h> +#include <vm/vm_map.h> +#include <vm/vm_extern.h> + +#include <sys/user.h> + +/* + * quick version of vm_fault + */ +void +vm_fault_quick(v, prot) + caddr_t v; + int prot; +{ + if (prot & VM_PROT_WRITE) + subyte(v, fubyte(v)); + else + fubyte(v); +} + +/* + * Finish a fork operation, with process p2 nearly set up. + * Copy and update the pcb, set up the stack so that the child + * ready to run and return to user mode. + */ +void +cpu_fork(p1, p2) + register struct proc *p1, *p2; +{ + struct user *up = p2->p_addr; + int i; + + p2->p_md.md_tf = p1->p_md.md_tf; + p2->p_md.md_flags = p1->p_md.md_flags & MDP_FPUSED; + + /* + * Cache the physical address of the pcb, so we can + * swap to it easily. + */ + p2->p_md.md_pcbpaddr = (void*) vtophys((vm_offset_t) &up->u_pcb); + + /* + * Simulate a write to the process's U-area pages, + * so that the system doesn't lose badly. + * (If this isn't done, the kernel can't read or + * write the kernel stack. "Ouch!") + */ + for (i = 0; i < UPAGES; i++) + pmap_emulate_reference(p2, (vm_offset_t)up + i * PAGE_SIZE, + 0, 1); + + /* + * Copy floating point state from the FP chip to the PCB + * if this process has state stored there. + */ + if (p1 == fpcurproc) { + alpha_pal_wrfen(1); + savefpstate(&fpcurproc->p_addr->u_pcb.pcb_fp); + alpha_pal_wrfen(0); + } + + /* + * Copy pcb and stack from proc p1 to p2. + * We do this as cheaply as possible, copying only the active + * part of the stack. The stack and pcb need to agree; + */ + p2->p_addr->u_pcb = p1->p_addr->u_pcb; + p2->p_addr->u_pcb.pcb_hw.apcb_usp = alpha_pal_rdusp(); + + /* + * Arrange for a non-local goto when the new process + * is started, to resume here, returning nonzero from setjmp. + */ +#ifdef DIAGNOSTIC + if (p1 != curproc) + panic("cpu_fork: curproc"); + if ((up->u_pcb.pcb_hw.apcb_flags & ALPHA_PCB_FLAGS_FEN) != 0) + printf("DANGER WILL ROBINSON: FEN SET IN cpu_fork!\n"); +#endif + + /* + * create the child's kernel stack, from scratch. + */ + { + struct trapframe *p2tf; + + /* + * Pick a stack pointer, leaving room for a trapframe; + * copy trapframe from parent so return to user mode + * will be to right address, with correct registers. + */ + p2tf = p2->p_md.md_tf = (struct trapframe *) + ((char *)p2->p_addr + USPACE - sizeof(struct trapframe)); + bcopy(p1->p_md.md_tf, p2->p_md.md_tf, + sizeof(struct trapframe)); + + /* + * Set up return-value registers as fork() libc stub expects. + */ + p2tf->tf_regs[FRAME_V0] = p1->p_pid; /* parent's pid */ + p2tf->tf_regs[FRAME_A3] = 0; /* no error */ + p2tf->tf_regs[FRAME_A4] = 1; /* is child */ + + /* + * Arrange for continuation at child_return(), which + * will return to exception_return(). Note that the child + * process doesn't stay in the kernel for long! + * + * This is an inlined version of cpu_set_kpc. + */ + up->u_pcb.pcb_hw.apcb_ksp = (u_int64_t)p2tf; + up->u_pcb.pcb_context[0] = + (u_int64_t)child_return; /* s0: pc */ + up->u_pcb.pcb_context[1] = + (u_int64_t)exception_return; /* s1: ra */ + up->u_pcb.pcb_context[2] = (u_long) p2; /* s2: a0 */ + up->u_pcb.pcb_context[7] = + (u_int64_t)switch_trampoline; /* ra: assembly magic */ + } +} + +/* + * Intercept the return address from a freshly forked process that has NOT + * been scheduled yet. + * + * This is needed to make kernel threads stay in kernel mode. + */ +void +cpu_set_fork_handler(p, func, arg) + struct proc *p; + void (*func) __P((void *)); + void *arg; +{ + /* + * Note that the trap frame follows the args, so the function + * is really called like this: func(arg, frame); + */ + p->p_addr->u_pcb.pcb_context[0] = (u_long) func; + p->p_addr->u_pcb.pcb_context[2] = (u_long) arg; +} + +/* + * cpu_exit is called as the last action during exit. + * We release the address space of the process, block interrupts, + * and call switch_exit. switch_exit switches to proc0's PCB and stack, + * then jumps into the middle of cpu_switch, as if it were switching + * from proc0. + */ +void +cpu_exit(p) + register struct proc *p; +{ + if (p == fpcurproc) + fpcurproc = NULL; + + (void) splhigh(); + cnt.v_swtch++; + cpu_switch(p); + panic("cpu_exit"); +} + +void +cpu_wait(p) + struct proc *p; +{ + /* drop per-process resources */ + pmap_dispose_proc(p); + + /* and clean-out the vmspace */ + vmspace_free(p->p_vmspace); +} + +/* + * Dump the machine specific header information at the start of a core dump. + */ +int +cpu_coredump(p, vp, cred) + struct proc *p; + struct vnode *vp; + struct ucred *cred; +{ + + return (vn_rdwr(UIO_WRITE, vp, (caddr_t) p->p_addr, ctob(UPAGES), + (off_t)0, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, + p)); +} + +#ifdef notyet +static void +setredzone(pte, vaddr) + u_short *pte; + caddr_t vaddr; +{ +/* eventually do this by setting up an expand-down stack segment + for ss0: selector, allowing stack access down to top of u. + this means though that protection violations need to be handled + thru a double fault exception that must do an integral task + switch to a known good context, within which a dump can be + taken. a sensible scheme might be to save the initial context + used by sched (that has physical memory mapped 1:1 at bottom) + and take the dump while still in mapped mode */ +} +#endif + +/* + * Map an IO request into kernel virtual address space. + * + * All requests are (re)mapped into kernel VA space. + * Notice that we use b_bufsize for the size of the buffer + * to be mapped. b_bcount might be modified by the driver. + */ +void +vmapbuf(bp) + register struct buf *bp; +{ + register caddr_t addr, v, kva; + vm_offset_t pa; + + if ((bp->b_flags & B_PHYS) == 0) + panic("vmapbuf"); + + for (v = bp->b_saveaddr, addr = (caddr_t)trunc_page(bp->b_data); + addr < bp->b_data + bp->b_bufsize; + addr += PAGE_SIZE, v += PAGE_SIZE) { + /* + * Do the vm_fault if needed; do the copy-on-write thing + * when reading stuff off device into memory. + */ + vm_fault_quick(addr, + (bp->b_flags&B_READ)?(VM_PROT_READ|VM_PROT_WRITE):VM_PROT_READ); + pa = trunc_page(pmap_kextract((vm_offset_t) addr)); + if (pa == 0) + panic("vmapbuf: page not present"); + vm_page_hold(PHYS_TO_VM_PAGE(pa)); + pmap_kenter((vm_offset_t) v, pa); + } + + kva = bp->b_saveaddr; + bp->b_saveaddr = bp->b_data; + bp->b_data = kva + (((vm_offset_t) bp->b_data) & PAGE_MASK); +} + +/* + * Free the io map PTEs associated with this IO operation. + * We also invalidate the TLB entries and restore the original b_addr. + */ +void +vunmapbuf(bp) + register struct buf *bp; +{ + register caddr_t addr; + vm_offset_t pa; + + if ((bp->b_flags & B_PHYS) == 0) + panic("vunmapbuf"); + + for (addr = (caddr_t)trunc_page(bp->b_data); + addr < bp->b_data + bp->b_bufsize; + addr += PAGE_SIZE) { + pa = trunc_page(pmap_kextract((vm_offset_t) addr)); + pmap_kremove((vm_offset_t) addr); + vm_page_unhold(PHYS_TO_VM_PAGE(pa)); + } + + bp->b_data = bp->b_saveaddr; +} + +/* + * Force reset the processor by invalidating the entire address space! + */ +void +cpu_reset() +{ + prom_halt(0); +} + +/* + * Grow the user stack to allow for 'sp'. This version grows the stack in + * chunks of SGROWSIZ. + */ +int +grow(p, sp) + struct proc *p; + size_t sp; +{ + unsigned int nss; + caddr_t v; + struct vmspace *vm = p->p_vmspace; + + if ((caddr_t)sp <= vm->vm_maxsaddr || sp >= (size_t) USRSTACK) + return (1); + + nss = roundup(USRSTACK - (unsigned)sp, PAGE_SIZE); + + if (nss > p->p_rlimit[RLIMIT_STACK].rlim_cur) + return (0); + + if (vm->vm_ssize && roundup(vm->vm_ssize << PAGE_SHIFT, + SGROWSIZ) < nss) { + int grow_amount; + /* + * If necessary, grow the VM that the stack occupies + * to allow for the rlimit. This allows us to not have + * to allocate all of the VM up-front in execve (which + * is expensive). + * Grow the VM by the amount requested rounded up to + * the nearest SGROWSIZ to provide for some hysteresis. + */ + grow_amount = roundup((nss - (vm->vm_ssize << PAGE_SHIFT)), SGROWSIZ); + v = (char *)USRSTACK - roundup(vm->vm_ssize << PAGE_SHIFT, + SGROWSIZ) - grow_amount; + /* + * If there isn't enough room to extend by SGROWSIZ, then + * just extend to the maximum size + */ + if (v < vm->vm_maxsaddr) { + v = vm->vm_maxsaddr; + grow_amount = MAXSSIZ - (vm->vm_ssize << PAGE_SHIFT); + } + if ((grow_amount == 0) || (vm_map_find(&vm->vm_map, NULL, 0, (vm_offset_t *)&v, + grow_amount, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0) != KERN_SUCCESS)) { + return (0); + } + vm->vm_ssize += grow_amount >> PAGE_SHIFT; + } + + return (1); +} + +static int cnt_prezero; + +SYSCTL_INT(_machdep, OID_AUTO, cnt_prezero, CTLFLAG_RD, &cnt_prezero, 0, ""); + +/* + * Implement the pre-zeroed page mechanism. + * This routine is called from the idle loop. + */ +int +vm_page_zero_idle() +{ + static int free_rover; + vm_page_t m; + int s; + + /* + * XXX + * We stop zeroing pages when there are sufficent prezeroed pages. + * This threshold isn't really needed, except we want to + * bypass unneeded calls to vm_page_list_find, and the + * associated cache flush and latency. The pre-zero will + * still be called when there are significantly more + * non-prezeroed pages than zeroed pages. The threshold + * of half the number of reserved pages is arbitrary, but + * approximately the right amount. Eventually, we should + * perhaps interrupt the zero operation when a process + * is found to be ready to run. + */ + if (cnt.v_free_count - vm_page_zero_count <= cnt.v_free_reserved / 2) + return (0); +#ifdef SMP + if (try_mplock()) { +#endif + s = splvm(); + m = vm_page_list_find(PQ_FREE, free_rover); + if (m != NULL) { + --(*vm_page_queues[m->queue].lcnt); + TAILQ_REMOVE(vm_page_queues[m->queue].pl, m, pageq); + m->queue = PQ_NONE; + splx(s); +#if 0 + rel_mplock(); +#endif + pmap_zero_page(VM_PAGE_TO_PHYS(m)); +#if 0 + get_mplock(); +#endif + (void)splvm(); + m->queue = PQ_ZERO + m->pc; + ++(*vm_page_queues[m->queue].lcnt); + TAILQ_INSERT_HEAD(vm_page_queues[m->queue].pl, m, + pageq); + free_rover = (free_rover + PQ_PRIME3) & PQ_L2_MASK; + ++vm_page_zero_count; + ++cnt_prezero; + } + splx(s); +#ifdef SMP + rel_mplock(); +#endif + return (1); +#ifdef SMP + } +#endif + return (0); +} + +/* + * Software interrupt handler for queued VM system processing. + */ +void +swi_vm() +{ +#if 0 + if (busdma_swi_pending != 0) + busdma_swi(); +#endif +} + +/* + * Tell whether this address is in some physical memory region. + * Currently used by the kernel coredump code in order to avoid + * dumping the ``ISA memory hole'' which could cause indefinite hangs, + * or other unpredictable behaviour. + */ + + +int +is_physical_memory(addr) + vm_offset_t addr; +{ + /* + * stuff other tests for known memory-mapped devices (PCI?) + * here + */ + + return 1; +} diff --git a/sys/powerpc/aim/vm_machdep.c b/sys/powerpc/aim/vm_machdep.c new file mode 100644 index 0000000..89edb49 --- /dev/null +++ b/sys/powerpc/aim/vm_machdep.c @@ -0,0 +1,516 @@ +/*- + * Copyright (c) 1982, 1986 The Regents of the University of California. + * Copyright (c) 1989, 1990 William Jolitz + * Copyright (c) 1994 John Dyson + * 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, and 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. + * + * from: @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91 + * Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$ + * $Id: vm_machdep.c,v 1.1 1998/06/10 10:53:40 dfr Exp $ + */ +/* + * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Chris G. Demetriou + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/buf.h> +#include <sys/vnode.h> +#include <sys/vmmeter.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> + +#include <machine/clock.h> +#include <machine/cpu.h> +#include <machine/md_var.h> +#include <machine/prom.h> + +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <vm/vm_prot.h> +#include <sys/lock.h> +#include <vm/vm_kern.h> +#include <vm/vm_page.h> +#include <vm/vm_map.h> +#include <vm/vm_extern.h> + +#include <sys/user.h> + +/* + * quick version of vm_fault + */ +void +vm_fault_quick(v, prot) + caddr_t v; + int prot; +{ + if (prot & VM_PROT_WRITE) + subyte(v, fubyte(v)); + else + fubyte(v); +} + +/* + * Finish a fork operation, with process p2 nearly set up. + * Copy and update the pcb, set up the stack so that the child + * ready to run and return to user mode. + */ +void +cpu_fork(p1, p2) + register struct proc *p1, *p2; +{ + struct user *up = p2->p_addr; + int i; + + p2->p_md.md_tf = p1->p_md.md_tf; + p2->p_md.md_flags = p1->p_md.md_flags & MDP_FPUSED; + + /* + * Cache the physical address of the pcb, so we can + * swap to it easily. + */ + p2->p_md.md_pcbpaddr = (void*) vtophys((vm_offset_t) &up->u_pcb); + + /* + * Simulate a write to the process's U-area pages, + * so that the system doesn't lose badly. + * (If this isn't done, the kernel can't read or + * write the kernel stack. "Ouch!") + */ + for (i = 0; i < UPAGES; i++) + pmap_emulate_reference(p2, (vm_offset_t)up + i * PAGE_SIZE, + 0, 1); + + /* + * Copy floating point state from the FP chip to the PCB + * if this process has state stored there. + */ + if (p1 == fpcurproc) { + alpha_pal_wrfen(1); + savefpstate(&fpcurproc->p_addr->u_pcb.pcb_fp); + alpha_pal_wrfen(0); + } + + /* + * Copy pcb and stack from proc p1 to p2. + * We do this as cheaply as possible, copying only the active + * part of the stack. The stack and pcb need to agree; + */ + p2->p_addr->u_pcb = p1->p_addr->u_pcb; + p2->p_addr->u_pcb.pcb_hw.apcb_usp = alpha_pal_rdusp(); + + /* + * Arrange for a non-local goto when the new process + * is started, to resume here, returning nonzero from setjmp. + */ +#ifdef DIAGNOSTIC + if (p1 != curproc) + panic("cpu_fork: curproc"); + if ((up->u_pcb.pcb_hw.apcb_flags & ALPHA_PCB_FLAGS_FEN) != 0) + printf("DANGER WILL ROBINSON: FEN SET IN cpu_fork!\n"); +#endif + + /* + * create the child's kernel stack, from scratch. + */ + { + struct trapframe *p2tf; + + /* + * Pick a stack pointer, leaving room for a trapframe; + * copy trapframe from parent so return to user mode + * will be to right address, with correct registers. + */ + p2tf = p2->p_md.md_tf = (struct trapframe *) + ((char *)p2->p_addr + USPACE - sizeof(struct trapframe)); + bcopy(p1->p_md.md_tf, p2->p_md.md_tf, + sizeof(struct trapframe)); + + /* + * Set up return-value registers as fork() libc stub expects. + */ + p2tf->tf_regs[FRAME_V0] = p1->p_pid; /* parent's pid */ + p2tf->tf_regs[FRAME_A3] = 0; /* no error */ + p2tf->tf_regs[FRAME_A4] = 1; /* is child */ + + /* + * Arrange for continuation at child_return(), which + * will return to exception_return(). Note that the child + * process doesn't stay in the kernel for long! + * + * This is an inlined version of cpu_set_kpc. + */ + up->u_pcb.pcb_hw.apcb_ksp = (u_int64_t)p2tf; + up->u_pcb.pcb_context[0] = + (u_int64_t)child_return; /* s0: pc */ + up->u_pcb.pcb_context[1] = + (u_int64_t)exception_return; /* s1: ra */ + up->u_pcb.pcb_context[2] = (u_long) p2; /* s2: a0 */ + up->u_pcb.pcb_context[7] = + (u_int64_t)switch_trampoline; /* ra: assembly magic */ + } +} + +/* + * Intercept the return address from a freshly forked process that has NOT + * been scheduled yet. + * + * This is needed to make kernel threads stay in kernel mode. + */ +void +cpu_set_fork_handler(p, func, arg) + struct proc *p; + void (*func) __P((void *)); + void *arg; +{ + /* + * Note that the trap frame follows the args, so the function + * is really called like this: func(arg, frame); + */ + p->p_addr->u_pcb.pcb_context[0] = (u_long) func; + p->p_addr->u_pcb.pcb_context[2] = (u_long) arg; +} + +/* + * cpu_exit is called as the last action during exit. + * We release the address space of the process, block interrupts, + * and call switch_exit. switch_exit switches to proc0's PCB and stack, + * then jumps into the middle of cpu_switch, as if it were switching + * from proc0. + */ +void +cpu_exit(p) + register struct proc *p; +{ + if (p == fpcurproc) + fpcurproc = NULL; + + (void) splhigh(); + cnt.v_swtch++; + cpu_switch(p); + panic("cpu_exit"); +} + +void +cpu_wait(p) + struct proc *p; +{ + /* drop per-process resources */ + pmap_dispose_proc(p); + + /* and clean-out the vmspace */ + vmspace_free(p->p_vmspace); +} + +/* + * Dump the machine specific header information at the start of a core dump. + */ +int +cpu_coredump(p, vp, cred) + struct proc *p; + struct vnode *vp; + struct ucred *cred; +{ + + return (vn_rdwr(UIO_WRITE, vp, (caddr_t) p->p_addr, ctob(UPAGES), + (off_t)0, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, + p)); +} + +#ifdef notyet +static void +setredzone(pte, vaddr) + u_short *pte; + caddr_t vaddr; +{ +/* eventually do this by setting up an expand-down stack segment + for ss0: selector, allowing stack access down to top of u. + this means though that protection violations need to be handled + thru a double fault exception that must do an integral task + switch to a known good context, within which a dump can be + taken. a sensible scheme might be to save the initial context + used by sched (that has physical memory mapped 1:1 at bottom) + and take the dump while still in mapped mode */ +} +#endif + +/* + * Map an IO request into kernel virtual address space. + * + * All requests are (re)mapped into kernel VA space. + * Notice that we use b_bufsize for the size of the buffer + * to be mapped. b_bcount might be modified by the driver. + */ +void +vmapbuf(bp) + register struct buf *bp; +{ + register caddr_t addr, v, kva; + vm_offset_t pa; + + if ((bp->b_flags & B_PHYS) == 0) + panic("vmapbuf"); + + for (v = bp->b_saveaddr, addr = (caddr_t)trunc_page(bp->b_data); + addr < bp->b_data + bp->b_bufsize; + addr += PAGE_SIZE, v += PAGE_SIZE) { + /* + * Do the vm_fault if needed; do the copy-on-write thing + * when reading stuff off device into memory. + */ + vm_fault_quick(addr, + (bp->b_flags&B_READ)?(VM_PROT_READ|VM_PROT_WRITE):VM_PROT_READ); + pa = trunc_page(pmap_kextract((vm_offset_t) addr)); + if (pa == 0) + panic("vmapbuf: page not present"); + vm_page_hold(PHYS_TO_VM_PAGE(pa)); + pmap_kenter((vm_offset_t) v, pa); + } + + kva = bp->b_saveaddr; + bp->b_saveaddr = bp->b_data; + bp->b_data = kva + (((vm_offset_t) bp->b_data) & PAGE_MASK); +} + +/* + * Free the io map PTEs associated with this IO operation. + * We also invalidate the TLB entries and restore the original b_addr. + */ +void +vunmapbuf(bp) + register struct buf *bp; +{ + register caddr_t addr; + vm_offset_t pa; + + if ((bp->b_flags & B_PHYS) == 0) + panic("vunmapbuf"); + + for (addr = (caddr_t)trunc_page(bp->b_data); + addr < bp->b_data + bp->b_bufsize; + addr += PAGE_SIZE) { + pa = trunc_page(pmap_kextract((vm_offset_t) addr)); + pmap_kremove((vm_offset_t) addr); + vm_page_unhold(PHYS_TO_VM_PAGE(pa)); + } + + bp->b_data = bp->b_saveaddr; +} + +/* + * Force reset the processor by invalidating the entire address space! + */ +void +cpu_reset() +{ + prom_halt(0); +} + +/* + * Grow the user stack to allow for 'sp'. This version grows the stack in + * chunks of SGROWSIZ. + */ +int +grow(p, sp) + struct proc *p; + size_t sp; +{ + unsigned int nss; + caddr_t v; + struct vmspace *vm = p->p_vmspace; + + if ((caddr_t)sp <= vm->vm_maxsaddr || sp >= (size_t) USRSTACK) + return (1); + + nss = roundup(USRSTACK - (unsigned)sp, PAGE_SIZE); + + if (nss > p->p_rlimit[RLIMIT_STACK].rlim_cur) + return (0); + + if (vm->vm_ssize && roundup(vm->vm_ssize << PAGE_SHIFT, + SGROWSIZ) < nss) { + int grow_amount; + /* + * If necessary, grow the VM that the stack occupies + * to allow for the rlimit. This allows us to not have + * to allocate all of the VM up-front in execve (which + * is expensive). + * Grow the VM by the amount requested rounded up to + * the nearest SGROWSIZ to provide for some hysteresis. + */ + grow_amount = roundup((nss - (vm->vm_ssize << PAGE_SHIFT)), SGROWSIZ); + v = (char *)USRSTACK - roundup(vm->vm_ssize << PAGE_SHIFT, + SGROWSIZ) - grow_amount; + /* + * If there isn't enough room to extend by SGROWSIZ, then + * just extend to the maximum size + */ + if (v < vm->vm_maxsaddr) { + v = vm->vm_maxsaddr; + grow_amount = MAXSSIZ - (vm->vm_ssize << PAGE_SHIFT); + } + if ((grow_amount == 0) || (vm_map_find(&vm->vm_map, NULL, 0, (vm_offset_t *)&v, + grow_amount, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0) != KERN_SUCCESS)) { + return (0); + } + vm->vm_ssize += grow_amount >> PAGE_SHIFT; + } + + return (1); +} + +static int cnt_prezero; + +SYSCTL_INT(_machdep, OID_AUTO, cnt_prezero, CTLFLAG_RD, &cnt_prezero, 0, ""); + +/* + * Implement the pre-zeroed page mechanism. + * This routine is called from the idle loop. + */ +int +vm_page_zero_idle() +{ + static int free_rover; + vm_page_t m; + int s; + + /* + * XXX + * We stop zeroing pages when there are sufficent prezeroed pages. + * This threshold isn't really needed, except we want to + * bypass unneeded calls to vm_page_list_find, and the + * associated cache flush and latency. The pre-zero will + * still be called when there are significantly more + * non-prezeroed pages than zeroed pages. The threshold + * of half the number of reserved pages is arbitrary, but + * approximately the right amount. Eventually, we should + * perhaps interrupt the zero operation when a process + * is found to be ready to run. + */ + if (cnt.v_free_count - vm_page_zero_count <= cnt.v_free_reserved / 2) + return (0); +#ifdef SMP + if (try_mplock()) { +#endif + s = splvm(); + m = vm_page_list_find(PQ_FREE, free_rover); + if (m != NULL) { + --(*vm_page_queues[m->queue].lcnt); + TAILQ_REMOVE(vm_page_queues[m->queue].pl, m, pageq); + m->queue = PQ_NONE; + splx(s); +#if 0 + rel_mplock(); +#endif + pmap_zero_page(VM_PAGE_TO_PHYS(m)); +#if 0 + get_mplock(); +#endif + (void)splvm(); + m->queue = PQ_ZERO + m->pc; + ++(*vm_page_queues[m->queue].lcnt); + TAILQ_INSERT_HEAD(vm_page_queues[m->queue].pl, m, + pageq); + free_rover = (free_rover + PQ_PRIME3) & PQ_L2_MASK; + ++vm_page_zero_count; + ++cnt_prezero; + } + splx(s); +#ifdef SMP + rel_mplock(); +#endif + return (1); +#ifdef SMP + } +#endif + return (0); +} + +/* + * Software interrupt handler for queued VM system processing. + */ +void +swi_vm() +{ +#if 0 + if (busdma_swi_pending != 0) + busdma_swi(); +#endif +} + +/* + * Tell whether this address is in some physical memory region. + * Currently used by the kernel coredump code in order to avoid + * dumping the ``ISA memory hole'' which could cause indefinite hangs, + * or other unpredictable behaviour. + */ + + +int +is_physical_memory(addr) + vm_offset_t addr; +{ + /* + * stuff other tests for known memory-mapped devices (PCI?) + * here + */ + + return 1; +} diff --git a/sys/powerpc/powerpc/vm_machdep.c b/sys/powerpc/powerpc/vm_machdep.c new file mode 100644 index 0000000..89edb49 --- /dev/null +++ b/sys/powerpc/powerpc/vm_machdep.c @@ -0,0 +1,516 @@ +/*- + * Copyright (c) 1982, 1986 The Regents of the University of California. + * Copyright (c) 1989, 1990 William Jolitz + * Copyright (c) 1994 John Dyson + * 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, and 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. + * + * from: @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91 + * Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$ + * $Id: vm_machdep.c,v 1.1 1998/06/10 10:53:40 dfr Exp $ + */ +/* + * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Chris G. Demetriou + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/buf.h> +#include <sys/vnode.h> +#include <sys/vmmeter.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> + +#include <machine/clock.h> +#include <machine/cpu.h> +#include <machine/md_var.h> +#include <machine/prom.h> + +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <vm/vm_prot.h> +#include <sys/lock.h> +#include <vm/vm_kern.h> +#include <vm/vm_page.h> +#include <vm/vm_map.h> +#include <vm/vm_extern.h> + +#include <sys/user.h> + +/* + * quick version of vm_fault + */ +void +vm_fault_quick(v, prot) + caddr_t v; + int prot; +{ + if (prot & VM_PROT_WRITE) + subyte(v, fubyte(v)); + else + fubyte(v); +} + +/* + * Finish a fork operation, with process p2 nearly set up. + * Copy and update the pcb, set up the stack so that the child + * ready to run and return to user mode. + */ +void +cpu_fork(p1, p2) + register struct proc *p1, *p2; +{ + struct user *up = p2->p_addr; + int i; + + p2->p_md.md_tf = p1->p_md.md_tf; + p2->p_md.md_flags = p1->p_md.md_flags & MDP_FPUSED; + + /* + * Cache the physical address of the pcb, so we can + * swap to it easily. + */ + p2->p_md.md_pcbpaddr = (void*) vtophys((vm_offset_t) &up->u_pcb); + + /* + * Simulate a write to the process's U-area pages, + * so that the system doesn't lose badly. + * (If this isn't done, the kernel can't read or + * write the kernel stack. "Ouch!") + */ + for (i = 0; i < UPAGES; i++) + pmap_emulate_reference(p2, (vm_offset_t)up + i * PAGE_SIZE, + 0, 1); + + /* + * Copy floating point state from the FP chip to the PCB + * if this process has state stored there. + */ + if (p1 == fpcurproc) { + alpha_pal_wrfen(1); + savefpstate(&fpcurproc->p_addr->u_pcb.pcb_fp); + alpha_pal_wrfen(0); + } + + /* + * Copy pcb and stack from proc p1 to p2. + * We do this as cheaply as possible, copying only the active + * part of the stack. The stack and pcb need to agree; + */ + p2->p_addr->u_pcb = p1->p_addr->u_pcb; + p2->p_addr->u_pcb.pcb_hw.apcb_usp = alpha_pal_rdusp(); + + /* + * Arrange for a non-local goto when the new process + * is started, to resume here, returning nonzero from setjmp. + */ +#ifdef DIAGNOSTIC + if (p1 != curproc) + panic("cpu_fork: curproc"); + if ((up->u_pcb.pcb_hw.apcb_flags & ALPHA_PCB_FLAGS_FEN) != 0) + printf("DANGER WILL ROBINSON: FEN SET IN cpu_fork!\n"); +#endif + + /* + * create the child's kernel stack, from scratch. + */ + { + struct trapframe *p2tf; + + /* + * Pick a stack pointer, leaving room for a trapframe; + * copy trapframe from parent so return to user mode + * will be to right address, with correct registers. + */ + p2tf = p2->p_md.md_tf = (struct trapframe *) + ((char *)p2->p_addr + USPACE - sizeof(struct trapframe)); + bcopy(p1->p_md.md_tf, p2->p_md.md_tf, + sizeof(struct trapframe)); + + /* + * Set up return-value registers as fork() libc stub expects. + */ + p2tf->tf_regs[FRAME_V0] = p1->p_pid; /* parent's pid */ + p2tf->tf_regs[FRAME_A3] = 0; /* no error */ + p2tf->tf_regs[FRAME_A4] = 1; /* is child */ + + /* + * Arrange for continuation at child_return(), which + * will return to exception_return(). Note that the child + * process doesn't stay in the kernel for long! + * + * This is an inlined version of cpu_set_kpc. + */ + up->u_pcb.pcb_hw.apcb_ksp = (u_int64_t)p2tf; + up->u_pcb.pcb_context[0] = + (u_int64_t)child_return; /* s0: pc */ + up->u_pcb.pcb_context[1] = + (u_int64_t)exception_return; /* s1: ra */ + up->u_pcb.pcb_context[2] = (u_long) p2; /* s2: a0 */ + up->u_pcb.pcb_context[7] = + (u_int64_t)switch_trampoline; /* ra: assembly magic */ + } +} + +/* + * Intercept the return address from a freshly forked process that has NOT + * been scheduled yet. + * + * This is needed to make kernel threads stay in kernel mode. + */ +void +cpu_set_fork_handler(p, func, arg) + struct proc *p; + void (*func) __P((void *)); + void *arg; +{ + /* + * Note that the trap frame follows the args, so the function + * is really called like this: func(arg, frame); + */ + p->p_addr->u_pcb.pcb_context[0] = (u_long) func; + p->p_addr->u_pcb.pcb_context[2] = (u_long) arg; +} + +/* + * cpu_exit is called as the last action during exit. + * We release the address space of the process, block interrupts, + * and call switch_exit. switch_exit switches to proc0's PCB and stack, + * then jumps into the middle of cpu_switch, as if it were switching + * from proc0. + */ +void +cpu_exit(p) + register struct proc *p; +{ + if (p == fpcurproc) + fpcurproc = NULL; + + (void) splhigh(); + cnt.v_swtch++; + cpu_switch(p); + panic("cpu_exit"); +} + +void +cpu_wait(p) + struct proc *p; +{ + /* drop per-process resources */ + pmap_dispose_proc(p); + + /* and clean-out the vmspace */ + vmspace_free(p->p_vmspace); +} + +/* + * Dump the machine specific header information at the start of a core dump. + */ +int +cpu_coredump(p, vp, cred) + struct proc *p; + struct vnode *vp; + struct ucred *cred; +{ + + return (vn_rdwr(UIO_WRITE, vp, (caddr_t) p->p_addr, ctob(UPAGES), + (off_t)0, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, + p)); +} + +#ifdef notyet +static void +setredzone(pte, vaddr) + u_short *pte; + caddr_t vaddr; +{ +/* eventually do this by setting up an expand-down stack segment + for ss0: selector, allowing stack access down to top of u. + this means though that protection violations need to be handled + thru a double fault exception that must do an integral task + switch to a known good context, within which a dump can be + taken. a sensible scheme might be to save the initial context + used by sched (that has physical memory mapped 1:1 at bottom) + and take the dump while still in mapped mode */ +} +#endif + +/* + * Map an IO request into kernel virtual address space. + * + * All requests are (re)mapped into kernel VA space. + * Notice that we use b_bufsize for the size of the buffer + * to be mapped. b_bcount might be modified by the driver. + */ +void +vmapbuf(bp) + register struct buf *bp; +{ + register caddr_t addr, v, kva; + vm_offset_t pa; + + if ((bp->b_flags & B_PHYS) == 0) + panic("vmapbuf"); + + for (v = bp->b_saveaddr, addr = (caddr_t)trunc_page(bp->b_data); + addr < bp->b_data + bp->b_bufsize; + addr += PAGE_SIZE, v += PAGE_SIZE) { + /* + * Do the vm_fault if needed; do the copy-on-write thing + * when reading stuff off device into memory. + */ + vm_fault_quick(addr, + (bp->b_flags&B_READ)?(VM_PROT_READ|VM_PROT_WRITE):VM_PROT_READ); + pa = trunc_page(pmap_kextract((vm_offset_t) addr)); + if (pa == 0) + panic("vmapbuf: page not present"); + vm_page_hold(PHYS_TO_VM_PAGE(pa)); + pmap_kenter((vm_offset_t) v, pa); + } + + kva = bp->b_saveaddr; + bp->b_saveaddr = bp->b_data; + bp->b_data = kva + (((vm_offset_t) bp->b_data) & PAGE_MASK); +} + +/* + * Free the io map PTEs associated with this IO operation. + * We also invalidate the TLB entries and restore the original b_addr. + */ +void +vunmapbuf(bp) + register struct buf *bp; +{ + register caddr_t addr; + vm_offset_t pa; + + if ((bp->b_flags & B_PHYS) == 0) + panic("vunmapbuf"); + + for (addr = (caddr_t)trunc_page(bp->b_data); + addr < bp->b_data + bp->b_bufsize; + addr += PAGE_SIZE) { + pa = trunc_page(pmap_kextract((vm_offset_t) addr)); + pmap_kremove((vm_offset_t) addr); + vm_page_unhold(PHYS_TO_VM_PAGE(pa)); + } + + bp->b_data = bp->b_saveaddr; +} + +/* + * Force reset the processor by invalidating the entire address space! + */ +void +cpu_reset() +{ + prom_halt(0); +} + +/* + * Grow the user stack to allow for 'sp'. This version grows the stack in + * chunks of SGROWSIZ. + */ +int +grow(p, sp) + struct proc *p; + size_t sp; +{ + unsigned int nss; + caddr_t v; + struct vmspace *vm = p->p_vmspace; + + if ((caddr_t)sp <= vm->vm_maxsaddr || sp >= (size_t) USRSTACK) + return (1); + + nss = roundup(USRSTACK - (unsigned)sp, PAGE_SIZE); + + if (nss > p->p_rlimit[RLIMIT_STACK].rlim_cur) + return (0); + + if (vm->vm_ssize && roundup(vm->vm_ssize << PAGE_SHIFT, + SGROWSIZ) < nss) { + int grow_amount; + /* + * If necessary, grow the VM that the stack occupies + * to allow for the rlimit. This allows us to not have + * to allocate all of the VM up-front in execve (which + * is expensive). + * Grow the VM by the amount requested rounded up to + * the nearest SGROWSIZ to provide for some hysteresis. + */ + grow_amount = roundup((nss - (vm->vm_ssize << PAGE_SHIFT)), SGROWSIZ); + v = (char *)USRSTACK - roundup(vm->vm_ssize << PAGE_SHIFT, + SGROWSIZ) - grow_amount; + /* + * If there isn't enough room to extend by SGROWSIZ, then + * just extend to the maximum size + */ + if (v < vm->vm_maxsaddr) { + v = vm->vm_maxsaddr; + grow_amount = MAXSSIZ - (vm->vm_ssize << PAGE_SHIFT); + } + if ((grow_amount == 0) || (vm_map_find(&vm->vm_map, NULL, 0, (vm_offset_t *)&v, + grow_amount, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0) != KERN_SUCCESS)) { + return (0); + } + vm->vm_ssize += grow_amount >> PAGE_SHIFT; + } + + return (1); +} + +static int cnt_prezero; + +SYSCTL_INT(_machdep, OID_AUTO, cnt_prezero, CTLFLAG_RD, &cnt_prezero, 0, ""); + +/* + * Implement the pre-zeroed page mechanism. + * This routine is called from the idle loop. + */ +int +vm_page_zero_idle() +{ + static int free_rover; + vm_page_t m; + int s; + + /* + * XXX + * We stop zeroing pages when there are sufficent prezeroed pages. + * This threshold isn't really needed, except we want to + * bypass unneeded calls to vm_page_list_find, and the + * associated cache flush and latency. The pre-zero will + * still be called when there are significantly more + * non-prezeroed pages than zeroed pages. The threshold + * of half the number of reserved pages is arbitrary, but + * approximately the right amount. Eventually, we should + * perhaps interrupt the zero operation when a process + * is found to be ready to run. + */ + if (cnt.v_free_count - vm_page_zero_count <= cnt.v_free_reserved / 2) + return (0); +#ifdef SMP + if (try_mplock()) { +#endif + s = splvm(); + m = vm_page_list_find(PQ_FREE, free_rover); + if (m != NULL) { + --(*vm_page_queues[m->queue].lcnt); + TAILQ_REMOVE(vm_page_queues[m->queue].pl, m, pageq); + m->queue = PQ_NONE; + splx(s); +#if 0 + rel_mplock(); +#endif + pmap_zero_page(VM_PAGE_TO_PHYS(m)); +#if 0 + get_mplock(); +#endif + (void)splvm(); + m->queue = PQ_ZERO + m->pc; + ++(*vm_page_queues[m->queue].lcnt); + TAILQ_INSERT_HEAD(vm_page_queues[m->queue].pl, m, + pageq); + free_rover = (free_rover + PQ_PRIME3) & PQ_L2_MASK; + ++vm_page_zero_count; + ++cnt_prezero; + } + splx(s); +#ifdef SMP + rel_mplock(); +#endif + return (1); +#ifdef SMP + } +#endif + return (0); +} + +/* + * Software interrupt handler for queued VM system processing. + */ +void +swi_vm() +{ +#if 0 + if (busdma_swi_pending != 0) + busdma_swi(); +#endif +} + +/* + * Tell whether this address is in some physical memory region. + * Currently used by the kernel coredump code in order to avoid + * dumping the ``ISA memory hole'' which could cause indefinite hangs, + * or other unpredictable behaviour. + */ + + +int +is_physical_memory(addr) + vm_offset_t addr; +{ + /* + * stuff other tests for known memory-mapped devices (PCI?) + * here + */ + + return 1; +} |