Integration of many changes done by Matthias Pfaller with a few by me.
clock.c * Removed definition of DELAY. intr.c * Removed an unneeded $Id:....$ locore.s * Moved some of the low level initialization code to machdep.c. * Defined proc_trampoline. * Changed sigcode to pass scp to SYS_sigreturn. * Changed copyin/copyout/fu*/su* to take advantage of the ns32532's dual address instructions. * Recoded copyinstr/copyoutstr/copystr in assembler. * Added a new and faster version of bzero. This makes bzero.s unnecessary. * Defined suswintr to make profiling work. * Recoded cpu_switch modelled after the i386 version of cpu_switch. * Added support for lazy fpu state restore to cpu_switch. * Recoded trap handling code to be more readable. * Added experimental code for single cacheline invalidation. machdep.c * Copied over cpu_startup from i386/i386/machdep.c. * Changed sys_sigreturn to take advantage of the argument passed by the trampoline code. * Changed boot to call doshutdownhooks and to store machine state in case of a panic. * Changed setregs to clear the fpu registers. * Recoded low_level_init. It's now called init532. * cpu_reset: New function, resets the machine. trap.c * Pulled over from i386/i386/trap.c. * Added support for lazy saved/restored fpu state. vm_machdep.c * Removed kstack double mapping by pulling over alot of code from i386/i386/vm_machdep.c. * Added support for lazy saved/restored fpu state. * Moved freeing of process resources from cpu_wait to cpu_exit. * Pulled over cpu_coredump, pagemove, vmapbuf and vunmapbuf from i386/i386/vm_machdep.c. pmap.c * Pulled over from i386/i386/pmap.c. genassym.c * Removed old and unused definitions, added new ones. sys_machdep.c * Moved sys_sysarch from machdep.c to sys_machdep.c. process_machdep.c * Changed to work without ktack double mapping. * Changed to work with lazy saved/restored fpu state.
This commit is contained in:
parent
9836ea60d6
commit
ccbcfbef91
|
@ -1,97 +0,0 @@
|
|||
/* $NetBSD: bzero.s,v 1.3 1996/01/26 08:11:47 phil Exp $ */
|
||||
|
||||
/*
|
||||
* Mach Operating System
|
||||
* Copyright (c) 1992 Carnegie Mellon University
|
||||
* Copyright (c) 1992 Helsinki University of Technology
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* 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 AND HELSINKI UNIVERSITY OF TECHNOLOGY ALLOW FREE USE
|
||||
* OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON AND
|
||||
* HELSINKI UNIVERSITY OF TECHNOLOGY DISCLAIM 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 Mellon
|
||||
* the rights to redistribute these changes.
|
||||
*/
|
||||
/*
|
||||
* File: ns532/bzero.s
|
||||
* Author: Tero Kivinen, Helsinki University of Technology 1992.
|
||||
*
|
||||
* $Id: bzero.s,v 1.3 1996/01/26 08:11:47 phil Exp $
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* bzero(char * addr, unsigned int length)
|
||||
*/
|
||||
|
||||
.text
|
||||
ENTRY(bzero)
|
||||
enter [],0
|
||||
movd B_ARG0,r1 /* addr */
|
||||
movd B_ARG1,r2 /* length */
|
||||
movd r1,r0 /* align addr */
|
||||
andd 3,r0
|
||||
cmpqd 0,r0
|
||||
beq wstart /* already aligned */
|
||||
negd r0,r0
|
||||
addqd 4,r0
|
||||
cmpd r0,r2
|
||||
bhi bytes /* not enough data to align */
|
||||
b1loop: movqb 0,0(r1) /* zero bytes */
|
||||
addqd 1,r1
|
||||
addqd -1,r2
|
||||
acbd -1,r0,b1loop
|
||||
wstart: movd r2,r0 /* length */
|
||||
lshd -6,r0
|
||||
cmpqd 0,r0
|
||||
beq phase2
|
||||
w1loop: movqd 0,0(r1) /* zero words */
|
||||
movqd 0,4(r1)
|
||||
movqd 0,8(r1)
|
||||
movqd 0,12(r1)
|
||||
movqd 0,16(r1)
|
||||
movqd 0,20(r1)
|
||||
movqd 0,24(r1)
|
||||
movqd 0,28(r1)
|
||||
movqd 0,32(r1)
|
||||
movqd 0,36(r1)
|
||||
movqd 0,40(r1)
|
||||
movqd 0,44(r1)
|
||||
movqd 0,48(r1)
|
||||
movqd 0,52(r1)
|
||||
movqd 0,56(r1)
|
||||
movqd 0,60(r1)
|
||||
addd 64,r1
|
||||
acbd -1,r0,w1loop
|
||||
phase2: movd r2,r0 /* length */
|
||||
andd 63,r0
|
||||
lshd -2,r0
|
||||
cmpqd 0,r0
|
||||
beq bytes
|
||||
w2loop: movqd 0,0(r1)
|
||||
addqd 4,r1
|
||||
acbd -1,r0,w2loop
|
||||
bytes: movd r2,r0 /* length */
|
||||
andd 3,r0
|
||||
cmpqd 0,r0
|
||||
beq done
|
||||
bloop: movqb 0,0(r1) /* zero bytes */
|
||||
addqd 1,r1
|
||||
acbb -1,r0,bloop
|
||||
done: exit []
|
||||
ret 0
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: clock.c,v 1.11 1995/05/16 07:30:46 phil Exp $ */
|
||||
/* $NetBSD: clock.c,v 1.12 1996/01/31 21:33:47 phil Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990 The Regents of the University of California.
|
||||
|
@ -82,13 +82,6 @@ spinwait(int millisecs)
|
|||
DELAY(5000 * millisecs);
|
||||
}
|
||||
|
||||
DELAY(n)
|
||||
{
|
||||
volatile int N = (n);
|
||||
while (--N > 0)
|
||||
;
|
||||
}
|
||||
|
||||
void
|
||||
setstatclockrate(int dummy)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: genassym.c,v 1.8 1995/06/09 05:59:58 phil Exp $ */
|
||||
/* $NetBSD: genassym.c,v 1.9 1996/01/31 21:33:52 phil Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1982, 1990 The Regents of the University of California.
|
||||
|
@ -45,80 +45,73 @@
|
|||
#include <vm/vm.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/trap.h>
|
||||
#include <machine/pmap.h>
|
||||
#include <machine/vmparam.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
main()
|
||||
{
|
||||
struct proc *p = (struct proc *)0;
|
||||
struct user *up = (struct user *)0;
|
||||
struct rusage *rup = (struct rusage *)0;
|
||||
struct uprof *uprof = (struct uprof *)0;
|
||||
struct pcb *pcb = (struct pcb *)0;
|
||||
struct on_stack *regs = (struct on_stack *)0;
|
||||
struct iv *iv = (struct iv *)0;
|
||||
struct proc *p = 0;
|
||||
struct vmmeter *vm = 0;
|
||||
struct pcb *pcb = 0;
|
||||
struct sigframe *sigf = 0;
|
||||
struct on_stack *regs = 0;
|
||||
struct iv *iv = 0;
|
||||
register unsigned i;
|
||||
|
||||
printf("#define\tKERNBASE 0x%x\n", KERNBASE);
|
||||
printf("#define\tUDOT_SZ %d\n", sizeof(struct user));
|
||||
printf("#define\tP_FORW %d\n", &p->p_forw);
|
||||
printf("#define\tP_BACK %d\n", &p->p_back);
|
||||
printf("#define\tP_VMSPACE %d\n", &p->p_vmspace);
|
||||
printf("#define\tP_ADDR %d\n", &p->p_addr);
|
||||
printf("#define\tP_PRIORITY %d\n", &p->p_priority);
|
||||
printf("#define\tP_STAT %d\n", &p->p_stat);
|
||||
printf("#define\tP_WCHAN %d\n", &p->p_wchan);
|
||||
printf("#define\tP_FLAG %d\n", &p->p_flag);
|
||||
printf("#define\tP_PID %d\n", &p->p_pid);
|
||||
#define def(N,V) printf("#define\t%s %d\n", N, V)
|
||||
|
||||
printf("#define\tSSLEEP %d\n", SSLEEP);
|
||||
printf("#define\tSRUN %d\n", SRUN);
|
||||
printf("#define\tUPAGES %d\n", UPAGES);
|
||||
printf("#define\tHIGHPAGES %d\n", HIGHPAGES);
|
||||
printf("#define\tCLSIZE %d\n", CLSIZE);
|
||||
printf("#define\tNBPG %d\n", NBPG);
|
||||
printf("#define\tNPTEPG %d\n", NPTEPG);
|
||||
printf("#define\tPGSHIFT %d\n", PGSHIFT);
|
||||
printf("#define\tSYSPTSIZE %d\n", SYSPTSIZE);
|
||||
printf("#define\tUSRPTSIZE %d\n", USRPTSIZE);
|
||||
def("SRUN", SRUN);
|
||||
|
||||
printf("#define\tKERN_STK_START 0x%x\n",
|
||||
USRSTACK + UPAGES*NBPG);
|
||||
printf("#define\tKSTK_SIZE %d\n", UPAGES*NBPG);
|
||||
printf("#define\tON_STK_SIZE %d\n", sizeof(struct on_stack));
|
||||
printf("#define\tREGS_USP %d\n", ®s->pcb_usp);
|
||||
printf("#define\tREGS_FP %d\n", ®s->pcb_fp);
|
||||
printf("#define\tREGS_SB %d\n", ®s->pcb_sb);
|
||||
printf("#define\tREGS_PSR %d\n", ®s->pcb_psr);
|
||||
def("PDSHIFT", PDSHIFT);
|
||||
def("PGSHIFT", PGSHIFT);
|
||||
def("PGOFSET", PGOFSET);
|
||||
def("NBPG", NBPG);
|
||||
|
||||
printf("#define\tPCB_ONSTACK %d\n", &pcb->pcb_onstack);
|
||||
printf("#define\tPCB_FSR %d\n", &pcb->pcb_fsr);
|
||||
def("PTDPTDI", PTDPTDI);
|
||||
def("KPTDI", KPTDI);
|
||||
def("NKPDE", NKPDE);
|
||||
def("APTDPTDI", APTDPTDI);
|
||||
def("KERNBASE", KERNBASE);
|
||||
|
||||
def("VM_MAXUSER_ADDRESS", VM_MAXUSER_ADDRESS);
|
||||
|
||||
def("P_ADDR", &p->p_addr);
|
||||
def("P_BACK", &p->p_back);
|
||||
def("P_FORW", &p->p_forw);
|
||||
def("P_PRIORITY", &p->p_priority);
|
||||
def("P_STAT", &p->p_stat);
|
||||
def("P_WCHAN", &p->p_wchan);
|
||||
def("P_VMSPACE", &p->p_vmspace);
|
||||
def("P_FLAG", &p->p_flag);
|
||||
def("P_PID", &p->p_pid);
|
||||
|
||||
def("V_INTR", &vm->v_intr);
|
||||
|
||||
def("PCB_ONSTACK", &pcb->pcb_onstack);
|
||||
def("PCB_FSR", &pcb->pcb_fsr);
|
||||
for (i=0; i<8; i++)
|
||||
printf("#define\tPCB_F%d %d\n", i, &pcb->pcb_freg[i]);
|
||||
printf("#define\tPCB_KSP %d\n", &pcb->pcb_ksp);
|
||||
printf("#define\tPCB_KFP %d\n", &pcb->pcb_kfp);
|
||||
printf("#define\tPCB_PTB %d\n", &pcb->pcb_ptb);
|
||||
printf("#define\tPCB_PL %d\n", &pcb->pcb_pl);
|
||||
printf("#define\tPCB_FLAGS %d\n", &pcb->pcb_flags);
|
||||
printf("#define\tPCB_ONFAULT %d\n", &pcb->pcb_onfault);
|
||||
def("PCB_KSP", &pcb->pcb_ksp);
|
||||
def("PCB_KFP", &pcb->pcb_kfp);
|
||||
def("PCB_PTB", &pcb->pcb_ptb);
|
||||
def("PCB_ONFAULT", &pcb->pcb_onfault);
|
||||
|
||||
printf("#define\tV_TRAP %d\n", &vm->v_trap);
|
||||
printf("#define\tV_INTR %d\n", &vm->v_intr);
|
||||
def("ON_STK_SIZE", sizeof(struct on_stack));
|
||||
def("REGS_USP", ®s->pcb_usp);
|
||||
def("REGS_FP", ®s->pcb_fp);
|
||||
def("REGS_SB", ®s->pcb_sb);
|
||||
def("REGS_PSR", ®s->pcb_psr);
|
||||
|
||||
printf("#define\tIV_VEC %d\n", &iv->iv_vec);
|
||||
printf("#define\tIV_ARG %d\n", &iv->iv_arg);
|
||||
printf("#define\tIV_CNT %d\n", &iv->iv_cnt);
|
||||
printf("#define\tIV_USE %d\n", &iv->iv_use);
|
||||
def("SIGF_HANDLER", &sigf->sf_handler);
|
||||
def("SIGF_SC", &sigf->sf_sc);
|
||||
|
||||
def("IV_VEC", &iv->iv_vec);
|
||||
def("IV_ARG", &iv->iv_arg);
|
||||
def("IV_CNT", &iv->iv_cnt);
|
||||
def("IV_USE", &iv->iv_use);
|
||||
|
||||
printf("#define\tUSRSTACK 0x%x\n", USRSTACK);
|
||||
#ifdef SYSVSHM
|
||||
printf("#define\tSHMMAXPGS %d\n", SHMMAXPGS);
|
||||
#endif
|
||||
printf("#define\tENOENT %d\n", ENOENT);
|
||||
printf("#define\tEFAULT %d\n", EFAULT);
|
||||
printf("#define\tENAMETOOLONG %d\n", ENAMETOOLONG);
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: intr.c,v 1.5 1995/09/26 20:16:26 phil Exp $ */
|
||||
/* $NetBSD: intr.c,v 1.6 1996/01/31 21:33:53 phil Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994 Matthias Pfaller.
|
||||
|
@ -28,8 +28,6 @@
|
|||
* 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: intr.c,v 1.5 1995/09/26 20:16:26 phil Exp $
|
||||
*/
|
||||
|
||||
#define DEFINE_SPLX
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: process_machdep.c,v 1.8 1995/09/26 20:16:32 phil Exp $ */
|
||||
/* $NetBSD: process_machdep.c,v 1.9 1996/01/31 21:34:02 phil Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1993 The Regents of the University of California.
|
||||
|
@ -73,17 +73,13 @@
|
|||
#include <machine/reg.h>
|
||||
#include <machine/frame.h>
|
||||
|
||||
extern struct proc *fpu_proc;
|
||||
|
||||
static inline struct reg *
|
||||
process_regs(p)
|
||||
struct proc *p;
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
if ((p->p_flag & P_INMEM) == 0)
|
||||
return (NULL);
|
||||
|
||||
ptr = (char *)p->p_addr + ((char *)p->p_md.md_regs - (char *)USRSTACK);
|
||||
return (ptr);
|
||||
return ((struct reg *) p->p_md.md_regs);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -127,6 +123,10 @@ process_read_fpregs(p, regs)
|
|||
if ((p->p_flag & P_INMEM) == 0)
|
||||
return (EIO);
|
||||
|
||||
if (fpu_proc == p) {
|
||||
save_fpu_context(&p->p_addr->u_pcb);
|
||||
fpu_proc = 0;
|
||||
}
|
||||
bcopy(&p->p_addr->u_pcb.pcb_fsr, regs, sizeof(*regs));
|
||||
return (0);
|
||||
}
|
||||
|
@ -139,7 +139,11 @@ process_write_fpregs(p, regs)
|
|||
if ((p->p_flag & P_INMEM) == 0)
|
||||
return (EIO);
|
||||
|
||||
if (fpu_proc == p)
|
||||
fpu_proc = 0;
|
||||
|
||||
bcopy(regs, &p->p_addr->u_pcb.pcb_fsr, sizeof(*regs));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: sys_machdep.c,v 1.5 1995/09/26 20:16:34 phil Exp $ */
|
||||
/* $NetBSD: sys_machdep.c,v 1.6 1996/01/31 21:34:03 phil Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990 The Regents of the University of California.
|
||||
|
@ -108,3 +108,17 @@ vdoualarm(arg)
|
|||
nvualarm--;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
sys_sysarch(p, v, retval)
|
||||
struct proc *p;
|
||||
void *v;
|
||||
register_t *retval;
|
||||
{
|
||||
struct sysarch_args /* {
|
||||
syscallarg(int) op;
|
||||
syscallarg(char *) parms;
|
||||
} */ *uap = v;
|
||||
|
||||
return ENOSYS;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* $NetBSD: trap.c,v 1.13 1995/06/09 06:00:10 phil Exp $ */
|
||||
/* $NetBSD: trap.c,v 1.14 1996/01/31 21:34:04 phil Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1996 Matthias Pfaller. All rights reserved.
|
||||
* Copyright (c) 1995 Charles M. Hannum. All rights reserved.
|
||||
* Copyright (c) 1990 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
@ -48,6 +50,7 @@
|
|||
#include <sys/user.h>
|
||||
#include <sys/acct.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/signal.h>
|
||||
#ifdef KTRACE
|
||||
#include <sys/ktrace.h>
|
||||
#endif
|
||||
|
@ -58,127 +61,242 @@
|
|||
#include <vm/vm_map.h>
|
||||
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/trap.h>
|
||||
#include <machine/cpufunc.h>
|
||||
#include <machine/psl.h>
|
||||
#include <machine/reg.h>
|
||||
#include <machine/trap.h>
|
||||
|
||||
struct proc *fpu_proc; /* Process owning the FPU. */
|
||||
|
||||
/*
|
||||
* Define the code needed before returning to user mode, for
|
||||
* trap and syscall.
|
||||
*/
|
||||
static inline void
|
||||
userret(p, pc, oticks)
|
||||
register struct proc *p;
|
||||
int pc;
|
||||
u_quad_t oticks;
|
||||
{
|
||||
int sig, s;
|
||||
|
||||
unsigned rcr2();
|
||||
extern short cpl;
|
||||
/* take pending signals */
|
||||
while ((sig = CURSIG(p)) != 0)
|
||||
postsig(sig);
|
||||
p->p_priority = p->p_usrpri;
|
||||
if (want_resched) {
|
||||
/*
|
||||
* Since we are curproc, a clock interrupt could
|
||||
* change our priority without changing run queues
|
||||
* (the running process is not kept on a run queue).
|
||||
* If this happened after we setrunqueue ourselves but
|
||||
* before we switch()'ed, we might not be on the queue
|
||||
* indicated by our priority.
|
||||
*/
|
||||
s = splstatclock();
|
||||
setrunqueue(p);
|
||||
p->p_stats->p_ru.ru_nivcsw++;
|
||||
mi_switch();
|
||||
splx(s);
|
||||
while ((sig = CURSIG(p)) != 0)
|
||||
postsig(sig);
|
||||
}
|
||||
|
||||
/*
|
||||
* If profiling, charge recent system time to the trapped pc.
|
||||
*/
|
||||
if (p->p_flag & P_PROFIL) {
|
||||
extern int psratio;
|
||||
|
||||
addupc_task(p, pc, (int)(p->p_sticks - oticks) * psratio);
|
||||
}
|
||||
|
||||
curpriority = p->p_priority;
|
||||
}
|
||||
|
||||
char *trap_type[] = {
|
||||
"non-vectored interrupt", /* 0 T_NVI */
|
||||
"non-maskable interrupt", /* 1 T_NMI */
|
||||
"abort trap", /* 2 T_ABT */
|
||||
"coprocessor trap", /* 3 T_SLAVE */
|
||||
"illegal operation in user mode", /* 4 T_ILL */
|
||||
"supervisor call", /* 5 T_SVC */
|
||||
"divide by zero", /* 6 T_DVZ */
|
||||
"flag instruction", /* 7 T_FLG */
|
||||
"breakpoint instruction", /* 8 T_BPT */
|
||||
"trace trap", /* 9 T_TRC */
|
||||
"undefined instruction", /* 10 T_UND */
|
||||
"restartable bus error", /* 11 T_RBE */
|
||||
"non-restartable bus error", /* 12 T_NBE */
|
||||
"integer overflow trap", /* 13 T_OVF */
|
||||
"debug trap", /* 14 T_DBG */
|
||||
"reserved trap", /* 15 T_RESERVED */
|
||||
"unused", /* 16 unused */
|
||||
"watchpoint", /* 17 T_WATCHPOINT */
|
||||
"asynchronous system trap" /* 18 T_AST */
|
||||
};
|
||||
int trap_types = sizeof trap_type / sizeof trap_type[0];
|
||||
|
||||
#ifdef DEBUG
|
||||
int trapdebug = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* trap(frame):
|
||||
* Exception, fault, and trap interface to BSD kernel. This
|
||||
* common code is called from assembly language IDT gate entry
|
||||
* common code is called from assembly language trap vector
|
||||
* routines that prepare a suitable stack frame, and restore this
|
||||
* frame after the exception has been processed. Note that the
|
||||
* effect is as if the arguments were passed call by reference.
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
trap(frame)
|
||||
struct trapframe frame;
|
||||
{
|
||||
register int i;
|
||||
register struct proc *p = curproc;
|
||||
struct timeval sticks;
|
||||
int ucode, type, tear, msr;
|
||||
int type = frame.tf_trapno;
|
||||
u_quad_t sticks;
|
||||
struct pcb *pcb;
|
||||
extern char fusubail[];
|
||||
#ifdef CINVSMALL
|
||||
extern char cinvstart[], cinvend[];
|
||||
#endif
|
||||
|
||||
cnt.v_trap++;
|
||||
|
||||
type = frame.tf_trapno;
|
||||
tear = frame.tf_tear;
|
||||
msr = frame.tf_msr;
|
||||
|
||||
if (curpcb->pcb_onfault && frame.tf_trapno != T_ABT) {
|
||||
copyfault:
|
||||
frame.tf_pc = (int)curpcb->pcb_onfault;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DDB
|
||||
if (curpcb && curpcb->pcb_onfault) {
|
||||
if (frame.tf_trapno == T_BPTFLT
|
||||
|| frame.tf_trapno == T_TRCTRAP)
|
||||
if (kdb_trap (type, 0, &frame))
|
||||
return;
|
||||
#ifdef DEBUG
|
||||
if (trapdebug) {
|
||||
printf("trap type=%d, pc=0x%x, tear=0x%x, msr=0x%x\n",
|
||||
type, frame.tf_pc, frame.tf_tear, frame.tf_msr);
|
||||
printf("curproc %x\n", curproc);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (curpcb == 0 || curproc == 0) goto we_re_toast;
|
||||
|
||||
if ((frame.tf_psr & PSL_USER) == PSL_USER) {
|
||||
if (USERMODE(frame.tf_psr)) {
|
||||
type |= T_USER;
|
||||
#ifdef notdef
|
||||
sticks = p->p_stime;
|
||||
#endif
|
||||
sticks = p->p_sticks;
|
||||
p->p_md.md_regs = (int *)&(frame.tf_reg);
|
||||
}
|
||||
|
||||
ucode = 0;
|
||||
|
||||
switch (type) {
|
||||
|
||||
default:
|
||||
we_re_toast:
|
||||
#ifdef KDB
|
||||
if (kdb_trap(&psl))
|
||||
return;
|
||||
#endif
|
||||
#ifdef DDB
|
||||
if (kdb_trap (type, 0, &frame))
|
||||
if (kdb_trap(type, 0, &frame))
|
||||
return;
|
||||
#endif
|
||||
|
||||
printf("bad trap: type=%d, pc=0x%x, tear=0x%x, msr=0x%x\n",
|
||||
if (frame.tf_trapno < trap_types)
|
||||
printf("fatal %s", trap_type[frame.tf_trapno]);
|
||||
else
|
||||
printf("unknown trap %d", frame.tf_trapno);
|
||||
printf(" in %s mode\n", (type & T_USER) ? "user" : "supervisor");
|
||||
printf("trap type=%d, pc=0x%x, tear=0x%x, msr=0x%x\n",
|
||||
type, frame.tf_pc, frame.tf_tear, frame.tf_msr);
|
||||
|
||||
panic("trap");
|
||||
/*NOTREACHED*/
|
||||
|
||||
case T_ABT: /* System level pagefault! */
|
||||
if (((msr & MSR_STT) == STT_SEQ_INS)
|
||||
|| ((msr & MSR_STT) == STT_NSQ_INS))
|
||||
{
|
||||
printf ("System pagefault: pc=0x%x, tear=0x%x, msr=0x%x\n",
|
||||
frame.tf_pc, frame.tf_tear, frame.tf_msr);
|
||||
goto we_re_toast;
|
||||
case T_UND | T_USER: { /* undefined instruction fault */
|
||||
int opcode, cfg;
|
||||
extern int _have_fpu;
|
||||
opcode = fubyte((void *)frame.tf_pc);
|
||||
#ifndef NS381
|
||||
if (!_have_fpu) {
|
||||
#ifdef MATH_EMULATE
|
||||
int rv;
|
||||
if ((rv = math_emulate(&frame)) == 0) {
|
||||
if (frame.tf_psr & PSL_T)
|
||||
goto trace;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
} else
|
||||
#endif
|
||||
if (opcode == 0x3e || opcode == 0xbe || opcode == 0xfe) {
|
||||
sprd(cfg, cfg);
|
||||
if ((cfg & CFG_F) == 0) {
|
||||
lprd(cfg, cfg | CFG_F);
|
||||
if (fpu_proc == p)
|
||||
return;
|
||||
pcb = &p->p_addr->u_pcb;
|
||||
if (fpu_proc != 0)
|
||||
save_fpu_context(&fpu_proc->p_addr->u_pcb);
|
||||
restore_fpu_context(pcb);
|
||||
fpu_proc = p;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* fall into */
|
||||
case T_ABT | T_USER: /* User level pagefault! */
|
||||
/* if (type == (T_ABT | T_USER))
|
||||
printf ("pagefault: pc=0x%x, tear=0x%x, msr=0x%x\n",
|
||||
frame.tf_pc, frame.tf_tear, frame.tf_msr); */
|
||||
{
|
||||
case T_ILL | T_USER: /* privileged instruction fault */
|
||||
trapsignal(p, SIGILL, type &~ T_USER);
|
||||
goto out;
|
||||
|
||||
case T_AST | T_USER: /* Allow process switch */
|
||||
cnt.v_soft++;
|
||||
if (p->p_flag & P_OWEUPC) {
|
||||
p->p_flag &= ~P_OWEUPC;
|
||||
ADDUPROF(p);
|
||||
}
|
||||
goto out;
|
||||
|
||||
case T_OVF | T_USER:
|
||||
case T_DVZ | T_USER:
|
||||
trapsignal(p, SIGFPE, type &~ T_USER);
|
||||
goto out;
|
||||
|
||||
case T_SLAVE | T_USER: {
|
||||
int fsr;
|
||||
#ifdef MATH_IEEE
|
||||
int rv;
|
||||
if ((rv = math_ieee(&frame)) == 0) {
|
||||
if (frame.tf_psr & PSL_T)
|
||||
goto trace;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
sfsr(fsr);
|
||||
trapsignal(p, SIGFPE, 0x80000000 | fsr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
case T_ABT: /* allow page faults in kernel mode */
|
||||
if ((frame.tf_msr & MSR_STT) == STT_SEQ_INS ||
|
||||
(frame.tf_msr & MSR_STT) == STT_NSQ_INS ||
|
||||
(p == 0))
|
||||
goto we_re_toast;
|
||||
pcb = &p->p_addr->u_pcb;
|
||||
/*
|
||||
* fusubail is used by [fs]uswintr() to prevent page faulting
|
||||
* from inside the profiling interrupt.
|
||||
*/
|
||||
if (pcb->pcb_onfault == fusubail)
|
||||
goto copyfault;
|
||||
#ifdef CINVSMALL
|
||||
/*
|
||||
* If a address translation for a cache invalidate
|
||||
* request fails, reset the pc and return.
|
||||
*/
|
||||
if ((unsigned int)frame.tf_pc >= (unsigned int)cinvstart &&
|
||||
(unsigned int)frame.tf_pc < (unsigned int)cinvend) {
|
||||
frame.tf_pc = (int)cinvend;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case T_ABT | T_USER: { /* page fault */
|
||||
register vm_offset_t va;
|
||||
register struct vmspace *vm = p->p_vmspace;
|
||||
register vm_map_t map;
|
||||
int rv;
|
||||
vm_prot_t ftype;
|
||||
extern vm_map_t kernel_map;
|
||||
unsigned nss,v;
|
||||
unsigned nss, v;
|
||||
|
||||
va = trunc_page((vm_offset_t)tear);
|
||||
/*
|
||||
* Avoid even looking at pde_v(va) for high va's. va's
|
||||
* above VM_MAX_KERNEL_ADDRESS don't correspond to normal
|
||||
* PDE's (half of them correspond to APDEpde and half to
|
||||
* an unmapped kernel PDE). va's betweeen 0xFEC00000 and
|
||||
* VM_MAX_KERNEL_ADDRESS correspond to unmapped kernel PDE's
|
||||
* (XXX - why are only 3 initialized when 6 are required to
|
||||
* reach VM_MAX_KERNEL_ADDRESS?). Faulting in an unmapped
|
||||
* kernel page table would give inconsistent PTD's.
|
||||
*
|
||||
* XXX - faulting in unmapped page tables wastes a page if
|
||||
* va turns out to be invalid.
|
||||
*
|
||||
* XXX - should "kernel address space" cover the kernel page
|
||||
* tables? Might have same problem with PDEpde as with
|
||||
* APDEpde (or there may be no problem with APDEpde).
|
||||
*/
|
||||
if (va > 0xFEBFF000) {
|
||||
v = KERN_FAILURE; /* becomes SIGBUS */
|
||||
goto nogo;
|
||||
}
|
||||
va = trunc_page((vm_offset_t)frame.tf_tear);
|
||||
/*
|
||||
* It is only a kernel address space fault iff:
|
||||
* 1. (type & T_USER) == 0 and
|
||||
|
@ -191,13 +309,13 @@ copyfault:
|
|||
map = kernel_map;
|
||||
else
|
||||
map = &vm->vm_map;
|
||||
if ((msr & MSR_DDT) == DDT_WRITE
|
||||
|| (msr & MSR_STT) == STT_RMW)
|
||||
if ((frame.tf_msr & MSR_DDT) == DDT_WRITE ||
|
||||
(frame.tf_msr & MSR_STT) == STT_RMW)
|
||||
ftype = VM_PROT_READ | VM_PROT_WRITE;
|
||||
else
|
||||
ftype = VM_PROT_READ;
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef DIAGNOSTIC
|
||||
if (map == kernel_map && va == 0) {
|
||||
printf("trap: bad kernel access at %x\n", va);
|
||||
goto we_re_toast;
|
||||
|
@ -208,363 +326,204 @@ copyfault:
|
|||
if ((caddr_t)va >= vm->vm_maxsaddr
|
||||
&& (caddr_t)va < (caddr_t)VM_MAXUSER_ADDRESS
|
||||
&& map != kernel_map) {
|
||||
nss = clrnd(btoc((unsigned)vm->vm_maxsaddr
|
||||
+ MAXSSIZ - (unsigned)va));
|
||||
nss = clrnd(btoc(USRSTACK-(unsigned)va));
|
||||
if (nss > btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur)) {
|
||||
/*pg("trap rlimit %d, maxsaddr %x va %x ", nss, vm->vm_maxsaddr, va);*/
|
||||
rv = KERN_FAILURE;
|
||||
goto nogo;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if page table is mapped, if not, fault it first */
|
||||
#define pde_v(v) (PTD[((v)>>PD_SHIFT)&1023].pd_v)
|
||||
if (!pde_v(va)) {
|
||||
if ((PTD[pdei(va)] & PG_V) == 0) {
|
||||
v = trunc_page(vtopte(va));
|
||||
rv = vm_fault(map, v, ftype, FALSE);
|
||||
if (rv != KERN_SUCCESS) goto nogo;
|
||||
if (rv != KERN_SUCCESS)
|
||||
goto nogo;
|
||||
/* check if page table fault, increment wiring */
|
||||
vm_map_pageable(map, v, round_page(v+1), FALSE);
|
||||
} else v=0;
|
||||
rv = vm_fault(map, va, ftype, FALSE);
|
||||
} else
|
||||
v = 0;
|
||||
|
||||
rv = vm_fault(map, va, ftype, FALSE);
|
||||
if (rv == KERN_SUCCESS) {
|
||||
/*
|
||||
* XXX: continuation of rude stack hack
|
||||
*/
|
||||
if (nss > vm->vm_ssize)
|
||||
vm->vm_ssize = nss;
|
||||
va = trunc_page(vtopte(va));
|
||||
/* for page table, increment wiring
|
||||
as long as not a page table fault as well */
|
||||
/* for page table, increment wiring as long as
|
||||
not a page table fault as well */
|
||||
if (!v && map != kernel_map)
|
||||
vm_map_pageable(map, va, round_page(va+1), FALSE);
|
||||
vm_map_pageable(map, va, round_page(va+1),
|
||||
FALSE);
|
||||
if (type == T_ABT)
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
nogo:
|
||||
|
||||
nogo:
|
||||
if (type == T_ABT) {
|
||||
if (curpcb->pcb_onfault)
|
||||
goto copyfault;
|
||||
printf("vm_fault(0x%x, 0x%x, 0x%x, 0) -> 0x%x\n",
|
||||
map, va, ftype, rv);
|
||||
printf(" type 0x%x, tear 0x%x msr 0x%x\n",
|
||||
type, tear, msr);
|
||||
goto we_re_toast;
|
||||
}
|
||||
i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV;
|
||||
break;
|
||||
}
|
||||
|
||||
case T_UND | T_USER: /* undefined instruction */
|
||||
case T_ILL | T_USER: /* Illegal instruction! */
|
||||
ucode = type &~ T_USER;
|
||||
i = SIGILL;
|
||||
break;
|
||||
|
||||
case T_NVI | T_USER: /* Non-vectored interrupt */
|
||||
case T_NMI | T_USER: /* non-maskable interrupt */
|
||||
case T_FLG | T_USER: /* flag instruction */
|
||||
goto we_re_toast;
|
||||
|
||||
case T_NBE | T_USER: /* non-restartable bus error */
|
||||
ucode = type &~ T_USER;
|
||||
i = SIGBUS;
|
||||
break;
|
||||
|
||||
case T_RBE | T_USER: /* restartable bus error */
|
||||
if (pcb->pcb_onfault != 0) {
|
||||
copyfault:
|
||||
frame.tf_pc = (int)curpcb->pcb_onfault;
|
||||
return;
|
||||
|
||||
case T_SLAVE | T_USER: /* coprocessor trap */
|
||||
ucode = type &~ T_USER;
|
||||
/* ucode = FPE_INTDIV_TRAP; */
|
||||
i = SIGFPE;
|
||||
}
|
||||
printf("vm_fault(%x, %x, %x, 0) -> %x\n",
|
||||
map, va, ftype, rv);
|
||||
goto we_re_toast;
|
||||
}
|
||||
trapsignal(p, (rv == KERN_PROTECTION_FAILURE)
|
||||
? SIGBUS : SIGSEGV, T_ABT);
|
||||
break;
|
||||
|
||||
case T_DVZ | T_USER: /* divide by zero */
|
||||
ucode = type &~ T_USER;
|
||||
/* ucode = FPE_INTDIV_TRAP; */
|
||||
i = SIGFPE;
|
||||
break;
|
||||
|
||||
case T_OVF | T_USER: /* integer overflow trap */
|
||||
ucode = type &~ T_USER;
|
||||
/* ucode = FPE_INTOVF_TRAP; */
|
||||
i = SIGFPE;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case T_TRC | T_USER: /* trace trap */
|
||||
case T_BPT | T_USER: /* breakpoint instruction */
|
||||
case T_DBG | T_USER: /* debug trap */
|
||||
trace:
|
||||
frame.tf_psr &= ~PSL_P;
|
||||
i = SIGTRAP;
|
||||
trapsignal(p, SIGTRAP, type &~ T_USER);
|
||||
break;
|
||||
|
||||
case T_INTERRUPT | T_USER: /* Allow Process Switch */
|
||||
/* if ((p->p_flag & SOWEUPC) && p->p_stats->p_prof.pr_scale) {
|
||||
addupc(frame.tf_eip, &p->p_stats->p_prof, 1);
|
||||
p->p_flag &= ~SOWEUPC;
|
||||
} */
|
||||
goto out;
|
||||
case T_NMI: /* non-maskable interrupt */
|
||||
case T_NMI | T_USER:
|
||||
#ifdef DDB
|
||||
/* NMI can be hooked up to a pushbutton for debugging */
|
||||
printf ("NMI ... going to debugger\n");
|
||||
if (kdb_trap (type, 0, &frame))
|
||||
return;
|
||||
#endif
|
||||
goto we_re_toast;
|
||||
}
|
||||
|
||||
} /* End of switch */
|
||||
|
||||
trapsignal(p, i, ucode);
|
||||
if ((type & T_USER) == 0)
|
||||
return;
|
||||
out:
|
||||
while (i = CURSIG(p))
|
||||
postsig(i);
|
||||
p->p_priority = p->p_usrpri;
|
||||
if (want_resched) {
|
||||
/*
|
||||
* Since we are curproc, clock will normally just change
|
||||
* our priority without moving us from one queue to another
|
||||
* (since the running process is not on a queue.)
|
||||
* If that happened after we setrunqueue ourselves but
|
||||
* before we switch()'ed, we might not be on the queue
|
||||
* indicated by our priority.
|
||||
*/
|
||||
(void) splstatclock();
|
||||
setrunqueue(p);
|
||||
p->p_stats->p_ru.ru_nivcsw++;
|
||||
mi_switch();
|
||||
(void) splnone();
|
||||
while (i = CURSIG(p))
|
||||
postsig(i);
|
||||
}
|
||||
if (p->p_stats->p_prof.pr_scale) {
|
||||
int ticks;
|
||||
|
||||
#ifdef YO_WHAT
|
||||
struct timeval *tv = &p->p_stime;
|
||||
|
||||
ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
|
||||
(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
|
||||
if (ticks) {
|
||||
#ifdef PROFTIMER
|
||||
extern int profscale;
|
||||
addupc(frame.tf_eip, &p->p_stats->p_prof,
|
||||
ticks * profscale);
|
||||
#else
|
||||
/* addupc(frame.tf_pc, &p->p_stats->p_prof, ticks); */
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
curpriority = p->p_priority;
|
||||
userret(p, frame.tf_pc, sticks);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* syscall(frame):
|
||||
* System call request from POSIX system call gate interface to kernel.
|
||||
* Like trap(), argument is call by reference.
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
syscall(frame)
|
||||
volatile struct syscframe frame;
|
||||
struct syscframe frame;
|
||||
{
|
||||
|
||||
register caddr_t params;
|
||||
register int i;
|
||||
register struct sysent *callp;
|
||||
register struct proc *p;
|
||||
struct timeval sticks;
|
||||
int error, opc, nsys;
|
||||
int args[8], rval[2];
|
||||
int code;
|
||||
size_t argsize;
|
||||
register_t code, args[8], rval[2];
|
||||
u_quad_t sticks;
|
||||
|
||||
cnt.v_syscall++;
|
||||
|
||||
/* is this a user? */
|
||||
if ((frame.sf_psr & PSL_USER) != PSL_USER)
|
||||
panic("syscall - process not in user mode.");
|
||||
|
||||
if (!USERMODE(frame.sf_psr))
|
||||
panic("syscall");
|
||||
p = curproc;
|
||||
#ifdef notdef
|
||||
sticks = p->p_stime;
|
||||
#endif
|
||||
code = frame.sf_reg[REG_R0];
|
||||
p->p_md.md_regs = (int *) & (frame.sf_reg);
|
||||
params = (caddr_t)frame.sf_usp + sizeof (int) ;
|
||||
|
||||
callp = p->p_emul->e_sysent;
|
||||
nsys = p->p_emul->e_nsysent;
|
||||
|
||||
/* Set new return address and save old one. */
|
||||
sticks = p->p_sticks;
|
||||
p->p_md.md_regs = (int *) &frame.sf_reg;
|
||||
opc = frame.sf_pc++;
|
||||
code = frame.sf_reg[REG_R0];
|
||||
|
||||
nsys = p->p_emul->e_nsysent;
|
||||
callp = p->p_emul->e_sysent;
|
||||
|
||||
params = (caddr_t)frame.sf_usp + sizeof(int);
|
||||
|
||||
switch (code) {
|
||||
case SYS_syscall:
|
||||
/*
|
||||
* Code is first argument, followed by actual args.
|
||||
*/
|
||||
code = fuword(params);
|
||||
params += sizeof(int);
|
||||
break;
|
||||
|
||||
case SYS___syscall:
|
||||
/*
|
||||
* Like syscall, but code is a quad, so as to maintain
|
||||
* quad alignment for the rest of the arguments.
|
||||
*/
|
||||
if (callp != sysent)
|
||||
break;
|
||||
code = fuword(params + _QUAD_LOWWORD * sizeof(int));
|
||||
params += sizeof(quad_t);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* do nothing by default */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Guard against bad sys call numbers! */
|
||||
if (code < 0 || code >= nsys)
|
||||
callp += p->p_emul->e_nosys; /* indir (illegal) */
|
||||
callp += p->p_emul->e_nosys; /* illegal */
|
||||
else
|
||||
callp += code;
|
||||
|
||||
if ((i = callp->sy_argsize) &&
|
||||
(error = copyin(params, (caddr_t)args, (u_int)i))) {
|
||||
frame.sf_reg[REG_R0] = error;
|
||||
frame.sf_psr |= PSL_C;
|
||||
argsize = callp->sy_argsize;
|
||||
if (argsize)
|
||||
error = copyin(params, (caddr_t)args, argsize);
|
||||
else
|
||||
error = 0;
|
||||
#ifdef SYSCALL_DEBUG
|
||||
scdebug_call(p, code, callp->sy_narg, i, args);
|
||||
scdebug_call(p, code, args);
|
||||
#endif
|
||||
#ifdef KTRACE
|
||||
if (KTRPOINT(p, KTR_SYSCALL))
|
||||
ktrsyscall(p->p_tracep, code, i, &args);
|
||||
#endif
|
||||
goto done;
|
||||
}
|
||||
#ifdef SYSCALL_DEBUG
|
||||
scdebug_call(p, code, callp->sy_narg, i, args);
|
||||
#endif
|
||||
#ifdef KTRACE
|
||||
if (KTRPOINT(p, KTR_SYSCALL))
|
||||
ktrsyscall(p->p_tracep, code, i, &args);
|
||||
ktrsyscall(p->p_tracep, code, argsize, args);
|
||||
#endif
|
||||
if (error)
|
||||
goto bad;
|
||||
rval[0] = 0;
|
||||
rval[1] = 0;
|
||||
rval[1] = frame.sf_reg[REG_R1];
|
||||
error = (*callp->sy_call)(p, args, rval);
|
||||
if (error == ERESTART)
|
||||
frame.sf_pc = opc;
|
||||
else if (error != EJUSTRETURN) {
|
||||
if (error) {
|
||||
frame.sf_reg[REG_R0] = error;
|
||||
frame.sf_psr |= PSL_C;
|
||||
} else {
|
||||
frame.sf_reg[REG_R0] = rval[0];
|
||||
frame.sf_reg[REG_R1] = rval[1];
|
||||
frame.sf_psr &= ~PSL_C;
|
||||
}
|
||||
}
|
||||
/* else if (error == EJUSTRETURN) */
|
||||
/* nothing to do */
|
||||
done:
|
||||
switch (error) {
|
||||
case 0:
|
||||
/*
|
||||
* Reinitialize proc pointer `p' as it may be different
|
||||
* if this is a child returning from fork syscall.
|
||||
*/
|
||||
p = curproc;
|
||||
while (i = CURSIG(p))
|
||||
postsig(i);
|
||||
p->p_priority = p->p_usrpri;
|
||||
if (want_resched) {
|
||||
frame.sf_reg[REG_R0] = rval[0];
|
||||
frame.sf_reg[REG_R1] = rval[1];
|
||||
frame.sf_psr &= ~PSL_C; /* carry bit */
|
||||
break;
|
||||
case ERESTART:
|
||||
/*
|
||||
* Since we are curproc, clock will normally just change
|
||||
* our priority without moving us from one queue to another
|
||||
* (since the running process is not on a queue.)
|
||||
* If that happened after we setrunqeue ourselves but before
|
||||
* we switch()'ed, we might not be on the queue indicated by
|
||||
* our priority.
|
||||
* Just reset the pc to the SVC instruction.
|
||||
*/
|
||||
(void) splstatclock();
|
||||
setrunqueue(p);
|
||||
p->p_stats->p_ru.ru_nivcsw++;
|
||||
mi_switch();
|
||||
(void) splnone();
|
||||
while (i = CURSIG(p))
|
||||
postsig(i);
|
||||
frame.sf_pc = opc;
|
||||
break;
|
||||
case EJUSTRETURN:
|
||||
/* nothing to do */
|
||||
break;
|
||||
default:
|
||||
bad:
|
||||
if (p->p_emul->e_errno)
|
||||
error = p->p_emul->e_errno[error];
|
||||
frame.sf_reg[REG_R0] = error;
|
||||
frame.sf_psr |= PSL_C; /* carry bit */
|
||||
break;
|
||||
}
|
||||
if (p->p_stats->p_prof.pr_scale) {
|
||||
int ticks;
|
||||
#ifdef YO_WHAT
|
||||
struct timeval *tv = &p->p_stime;
|
||||
|
||||
ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
|
||||
(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
|
||||
if (ticks) {
|
||||
#ifdef PROFTIMER
|
||||
extern int profscale;
|
||||
addupc(frame.sf_pc, &p->p_stats->p_prof,
|
||||
ticks * profscale);
|
||||
#else
|
||||
/* addupc(frame.sf_pc, &p->p_stats->p_prof, ticks); */
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
curpriority = p->p_priority;
|
||||
#ifdef SYSCALL_DEBUG
|
||||
scdebug_ret(p, code, error, rval[0]);
|
||||
scdebug_ret(p, code, error, rval);
|
||||
#endif
|
||||
userret(p, frame.sf_pc, sticks);
|
||||
#ifdef KTRACE
|
||||
if (KTRPOINT(p, KTR_SYSRET))
|
||||
ktrsysret(p->p_tracep, code, error, rval[0]);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* For the child, do the stuff after mi_swtch() in syscall so
|
||||
low_level_fork does not have to rethread the kernel stack. */
|
||||
void
|
||||
ll_fork_sig()
|
||||
child_return(p, frame)
|
||||
struct proc *p;
|
||||
struct syscframe frame;
|
||||
{
|
||||
register struct proc *p = curproc;
|
||||
int i;
|
||||
frame.sf_reg[REG_R0] = 0;
|
||||
frame.sf_psr &= ~PSL_C;
|
||||
|
||||
(void) splnone();
|
||||
while (i = CURSIG(p))
|
||||
postsig(i);
|
||||
}
|
||||
|
||||
|
||||
/* #define dbg_user */
|
||||
/* Other stuff.... */
|
||||
int
|
||||
check_user_write ( u_long addr, u_long size)
|
||||
{
|
||||
int rv;
|
||||
vm_offset_t va;
|
||||
|
||||
#ifdef dbg_user
|
||||
printf ("ck_ur_wr: addr=0x%x, size=0x%x", addr, size);
|
||||
#endif
|
||||
/* check for all possible places! */
|
||||
va = trunc_page((vm_offset_t) addr);
|
||||
if (va > VM_MAXUSER_ADDRESS) return (1);
|
||||
|
||||
while ((u_long)va < (addr + size)) {
|
||||
/* check for copy on write access. */
|
||||
#ifdef dbg_user
|
||||
printf (" (0x%x:%d)", va, vtopte(va)->pg_prot);
|
||||
#endif
|
||||
if (!(vtopte(va)->pg_v) || vtopte(va)->pg_prot != 3 ) {
|
||||
#ifdef dbg_user
|
||||
printf (" fault");
|
||||
#endif
|
||||
rv = vm_fault(&curproc->p_vmspace->vm_map, va,
|
||||
VM_PROT_READ | VM_PROT_WRITE, FALSE);
|
||||
if (rv != KERN_SUCCESS)
|
||||
#ifdef dbg_user
|
||||
{ printf (" bad\n");
|
||||
#endif
|
||||
return(1);
|
||||
#ifdef dbg_user
|
||||
}
|
||||
#endif
|
||||
}
|
||||
va += NBPG;
|
||||
}
|
||||
#ifdef dbg_user
|
||||
printf ("\n");
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
userret(p, frame.sf_pc, 0);
|
||||
#ifdef KTRACE
|
||||
if (KTRPOINT(p, KTR_SYSRET))
|
||||
ktrsysret(p->p_tracep, SYS_fork, 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
/* $NetBSD: vm_machdep.c,v 1.11 1995/08/29 22:37:54 phil Exp $ */
|
||||
/* $NetBSD: vm_machdep.c,v 1.12 1996/01/31 21:34:06 phil Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1996 Matthias Pfaller.
|
||||
* Copyright (c) 1995 Charles M. Hannum. All rights reserved.
|
||||
* Copyright (c) 1993 Philip A. Nelson.
|
||||
* Copyright (c) 1982, 1986 The Regents of the University of California.
|
||||
* Copyright (c) 1989, 1990 William Jolitz
|
||||
* All rights reserved.
|
||||
|
@ -54,120 +57,140 @@
|
|||
#include <vm/vm_kern.h>
|
||||
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/cpufunc.h>
|
||||
|
||||
extern struct proc *fpu_proc;
|
||||
|
||||
/*
|
||||
* Finish a fork operation, with process p2 nearly set up.
|
||||
* Copy and update the kernel stack and pcb, making the child
|
||||
* ready to run, and marking it so that it can return differently
|
||||
* than the parent. Returns 1 in the child process, 0 in the parent.
|
||||
* We currently double-map the user area so that the stack is at the same
|
||||
* address in each process; in the future we will probably relocate
|
||||
* the frame pointers on the stack after copying.
|
||||
* Copy the pcb and setup the kernel stack for the child.
|
||||
* Setup the child's stackframe to return to child_return
|
||||
* via proc_trampoline from cpu_switch.
|
||||
*/
|
||||
cpu_fork(p1, p2)
|
||||
register struct proc *p1, *p2;
|
||||
{
|
||||
struct user *up = p2->p_addr;
|
||||
int foo, offset, addr, i;
|
||||
register struct pcb *pcb = &p2->p_addr->u_pcb;
|
||||
register struct syscframe *tf;
|
||||
register struct switchframe *sf;
|
||||
extern void proc_trampoline(), child_return();
|
||||
|
||||
/* Copy curpcb (which is presumably p1's PCB) to p2. */
|
||||
*pcb = p1->p_addr->u_pcb;
|
||||
pcb->pcb_onstack = (struct on_stack *)((u_int)p2->p_addr + USPACE) - 1;
|
||||
*pcb->pcb_onstack = *p1->p_addr->u_pcb.pcb_onstack;
|
||||
/* If p1 is holding the FPU, update the FPU context of p2. */
|
||||
if (fpu_proc == p1)
|
||||
save_fpu_context(pcb);
|
||||
pmap_activate(&p2->p_vmspace->vm_pmap, pcb);
|
||||
|
||||
/*
|
||||
* Copy pcb from proc p1 to p2.
|
||||
* _low_level_init will copy the kernel stack as cheeply as
|
||||
* possible.
|
||||
* Copy the syscframe, and arrange for the child to return directly
|
||||
* through rei().
|
||||
*/
|
||||
p2->p_addr->u_pcb = p1->p_addr->u_pcb;
|
||||
p2->p_addr->u_pcb.pcb_onstack =
|
||||
(struct on_stack *) p2->p_addr + USPACE
|
||||
- sizeof (struct on_stack);
|
||||
|
||||
/*
|
||||
* Wire top of address space of child to it's kstack.
|
||||
* First, fault in a page of pte's to map it.
|
||||
*/
|
||||
addr = trunc_page((u_int)vtopte(USRSTACK));
|
||||
vm_map_pageable(&p2->p_vmspace->vm_map, addr, addr+USPACE, FALSE);
|
||||
for (i=0; i < UPAGES; i++)
|
||||
pmap_enter(&p2->p_vmspace->vm_pmap, USRSTACK+i*NBPG,
|
||||
pmap_extract(pmap_kernel(), ((int)p2->p_addr)+i*NBPG),
|
||||
VM_PROT_READ, TRUE);
|
||||
|
||||
pmap_activate(&p2->p_vmspace->vm_pmap, &up->u_pcb);
|
||||
|
||||
/*
|
||||
* Low_level_fork returns twice! First with a 0 in the
|
||||
* parent space and Second with a 1 in the child.
|
||||
*/
|
||||
|
||||
return (low_level_fork(up));
|
||||
tf = (struct syscframe *)((u_int)p2->p_addr + USPACE) - 1;
|
||||
p2->p_md.md_regs = (int *)&(tf->sf_reg);
|
||||
sf = (struct switchframe *)tf - 1;
|
||||
sf->sf_pc = (long) proc_trampoline;
|
||||
sf->sf_fp = (long) &tf->sf_fp;
|
||||
sf->sf_reg[REG_R3] = (long) child_return;
|
||||
sf->sf_reg[REG_R4] = (long) p2;
|
||||
sf->sf_pl = imask[IPL_ZERO];
|
||||
pcb->pcb_ksp = (long) sf;
|
||||
pcb->pcb_kfp = (long) &sf->sf_fp;
|
||||
}
|
||||
|
||||
/*
|
||||
* cpu_set_kpc:
|
||||
*
|
||||
* Arrange for in-kernel execution of a process to continue at the
|
||||
* named pc, as if the code at that address were called as a function
|
||||
* with argument, the current process's process pointer.
|
||||
*
|
||||
* Note that it's assumed that when the named process returns, rei()
|
||||
* should be invoked, to return to user mode.
|
||||
*/
|
||||
void
|
||||
cpu_set_kpc(p, pc)
|
||||
struct proc *p;
|
||||
u_long pc;
|
||||
{
|
||||
struct pcb *pcbp;
|
||||
struct switchframe *sf;
|
||||
extern void proc_trampoline();
|
||||
|
||||
#ifdef notyet
|
||||
pcbp = &p->p_addr->u_pcb;
|
||||
sf = (struct switchframe *) pcbp->pcb_ksp;
|
||||
sf->sf_pc = (long) proc_trampoline;
|
||||
sf->sf_reg[REG_R3] = pc;
|
||||
sf->sf_reg[REG_R4] = (long) p;
|
||||
}
|
||||
|
||||
/*
|
||||
* cpu_swapout is called immediately before a process's 'struct user'
|
||||
* and kernel stack are unwired (which are in turn done immediately
|
||||
* before it's P_INMEM flag is cleared). If the process is the
|
||||
* current owner of the floating point unit, the FP state has to be
|
||||
* saved, so that it goes out with the pcb, which is in the user area.
|
||||
*/
|
||||
void
|
||||
cpu_swapout(p)
|
||||
struct proc *p;
|
||||
{
|
||||
/*
|
||||
* Make sure we save the FP state before the user area vanishes.
|
||||
*/
|
||||
if (fpu_proc != p)
|
||||
return;
|
||||
save_fpu_context(&p->p_addr->u_pcb);
|
||||
fpu_proc = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* cpu_exit is called as the last action during exit.
|
||||
*
|
||||
* We change to an inactive address space and a "safe" stack,
|
||||
* passing thru an argument to the new stack. Now, safely isolated
|
||||
* from the resources we're shedding, we release the address space
|
||||
* and any remaining machine-dependent resources, including the
|
||||
* memory for the user structure and kernel stack.
|
||||
*
|
||||
* Next, we assign a dummy context to be written over by swtch,
|
||||
* calling it to send this process off to oblivion.
|
||||
* [The nullpcb allows us to minimize cost in swtch() by not having
|
||||
* a special case].
|
||||
* We switch to a temorary stack and address space. Then we release
|
||||
* release the original address space and machine-dependent resources,
|
||||
* including the memory for the user structure and kernel stack.
|
||||
* Once finished, we call cpu_exit, which never returns.
|
||||
* We block interrupts until cpu_switch has made things safe again.
|
||||
*/
|
||||
struct proc *swtch_to_inactive();
|
||||
|
||||
void
|
||||
cpu_exit(p)
|
||||
register struct proc *p;
|
||||
cpu_exit(arg)
|
||||
struct proc *arg;
|
||||
{
|
||||
static struct pcb nullpcb; /* pcb to overwrite on last swtch */
|
||||
register struct proc *p __asm("r3");
|
||||
cnt.v_swtch++;
|
||||
|
||||
/* free cporcessor (if we have it) */
|
||||
if( p == npxproc) npxproc =0;
|
||||
/* Copy arg into a register. */
|
||||
movd(arg, p);
|
||||
|
||||
/* move to inactive space and stack, passing arg accross */
|
||||
p = swtch_to_inactive(p);
|
||||
/* If we were using the FPU, forget about it. */
|
||||
if (fpu_proc == p)
|
||||
fpu_proc = 0;
|
||||
|
||||
/* drop per-process resources */
|
||||
/* Switch to temporary stack and address space. */
|
||||
lprd(sp, INTSTACK);
|
||||
load_ptb(PTDpaddr);
|
||||
|
||||
/* Free resources. */
|
||||
vmspace_free(p->p_vmspace);
|
||||
kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
|
||||
(void) splhigh();
|
||||
kmem_free(kernel_map, (vm_offset_t)p->p_addr, USPACE);
|
||||
|
||||
p->p_addr = (struct user *) &nullpcb;
|
||||
splstatclock();
|
||||
/* Don't update pcb in cpu_switch. */
|
||||
curproc = NULL;
|
||||
cpu_switch();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
#else
|
||||
void
|
||||
cpu_exit(p)
|
||||
register struct proc *p;
|
||||
{
|
||||
|
||||
splstatclock();
|
||||
cpu_switch();
|
||||
/* Not reached. */
|
||||
panic ("cpu_exit! swtch returned!");
|
||||
}
|
||||
|
||||
void
|
||||
cpu_wait(p)
|
||||
struct proc *p;
|
||||
{
|
||||
|
||||
/* drop per-process resources */
|
||||
vmspace_free(p->p_vmspace);
|
||||
kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Dump the machine specific segment at the start of a core dump.
|
||||
*/
|
||||
struct md_core {
|
||||
struct reg intreg;
|
||||
struct fpreg freg;
|
||||
};
|
||||
int
|
||||
cpu_coredump(p, vp, cred, chdr)
|
||||
struct proc *p;
|
||||
|
@ -175,38 +198,43 @@ cpu_coredump(p, vp, cred, chdr)
|
|||
struct ucred *cred;
|
||||
struct core *chdr;
|
||||
{
|
||||
int error;
|
||||
struct {
|
||||
struct reg regs;
|
||||
struct fpreg fpregs;
|
||||
} cpustate;
|
||||
struct md_core md_core;
|
||||
struct coreseg cseg;
|
||||
int error;
|
||||
|
||||
CORE_SETMAGIC(*chdr, COREMAGIC, MID_NS32532, 0);
|
||||
chdr->c_hdrsize = ALIGN(sizeof(*chdr));
|
||||
chdr->c_seghdrsize = ALIGN(sizeof(cseg));
|
||||
chdr->c_cpusize = sizeof(cpustate);
|
||||
cpustate.regs = *((struct reg *)p->p_md.md_regs);
|
||||
cpustate.fpregs = *((struct fpreg *)&p->p_addr->u_pcb.pcb_fsr);
|
||||
chdr->c_cpusize = sizeof(md_core);
|
||||
|
||||
/* Save integer registers. */
|
||||
error = process_read_regs(p, &md_core.intreg);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* Save floating point registers. */
|
||||
error = process_read_fpregs(p, &md_core.freg);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
CORE_SETMAGIC(cseg, CORESEGMAGIC, MID_NS32532, CORE_CPU);
|
||||
cseg.c_addr = 0;
|
||||
cseg.c_size = chdr->c_cpusize;
|
||||
|
||||
error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&cseg, chdr->c_seghdrsize,
|
||||
(off_t)chdr->c_hdrsize, UIO_SYSSPACE,
|
||||
IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, p);
|
||||
(off_t)chdr->c_hdrsize, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred,
|
||||
(int *)0, p);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&cpustate, sizeof(cpustate),
|
||||
error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&md_core, sizeof(md_core),
|
||||
(off_t)(chdr->c_hdrsize + chdr->c_seghdrsize), UIO_SYSSPACE,
|
||||
IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, p);
|
||||
|
||||
if (!error)
|
||||
chdr->c_nseg++;
|
||||
|
||||
IO_NODELOCKED|IO_UNIT, cred, (int *)0, p);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
chdr->c_nseg++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -236,7 +264,7 @@ pagemove(from, to, size)
|
|||
register caddr_t from, to;
|
||||
int size;
|
||||
{
|
||||
register struct pte *fpte, *tpte;
|
||||
int *fpte, *tpte;
|
||||
|
||||
if (size % CLBYTES)
|
||||
panic("pagemove");
|
||||
|
@ -249,7 +277,7 @@ pagemove(from, to, size)
|
|||
to += NBPG;
|
||||
size -= NBPG;
|
||||
}
|
||||
tlbflush();
|
||||
pmap_update();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -259,6 +287,7 @@ kvtop(addr)
|
|||
register caddr_t addr;
|
||||
{
|
||||
vm_offset_t va;
|
||||
|
||||
va = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
|
||||
if (va == 0)
|
||||
panic("kvtop: zero page frame");
|
||||
|
@ -285,62 +314,49 @@ extern vm_map_t phys_map;
|
|||
* All requests are (re)mapped into kernel VA space via the useriomap
|
||||
* (a name with only slightly more meaning than "kernelmap")
|
||||
*/
|
||||
vmapbuf(bp)
|
||||
register struct buf *bp;
|
||||
vmapbuf(bp, len)
|
||||
struct buf *bp;
|
||||
vm_size_t len;
|
||||
{
|
||||
register int npf;
|
||||
register caddr_t addr;
|
||||
register long flags = bp->b_flags;
|
||||
struct proc *p;
|
||||
int off;
|
||||
vm_offset_t kva;
|
||||
register vm_offset_t pa;
|
||||
vm_offset_t faddr, taddr, off;
|
||||
pt_entry_t *fpte, *tpte;
|
||||
pt_entry_t *pmap_pte __P((pmap_t, vm_offset_t));
|
||||
|
||||
if ((flags & B_PHYS) == 0)
|
||||
if ((bp->b_flags & B_PHYS) == 0)
|
||||
panic("vmapbuf");
|
||||
addr = bp->b_saveaddr = bp->b_un.b_addr;
|
||||
off = (int)addr & PGOFSET;
|
||||
p = bp->b_proc;
|
||||
npf = btoc(round_page(bp->b_bcount + off));
|
||||
kva = kmem_alloc_wait(phys_map, ctob(npf));
|
||||
bp->b_un.b_addr = (caddr_t) (kva + off);
|
||||
while (npf--) {
|
||||
pa = pmap_extract(&p->p_vmspace->vm_pmap, (vm_offset_t)addr);
|
||||
if (pa == 0)
|
||||
panic("vmapbuf: null page frame");
|
||||
pmap_enter(vm_map_pmap(phys_map), kva, trunc_page(pa),
|
||||
VM_PROT_READ|VM_PROT_WRITE, TRUE);
|
||||
addr += PAGE_SIZE;
|
||||
kva += PAGE_SIZE;
|
||||
}
|
||||
faddr = trunc_page(bp->b_saveaddr = bp->b_data);
|
||||
off = (vm_offset_t)bp->b_data - faddr;
|
||||
len = round_page(off + len);
|
||||
taddr = kmem_alloc_wait(phys_map, len);
|
||||
bp->b_data = (caddr_t)(taddr + off);
|
||||
/*
|
||||
* The region is locked, so we expect that pmap_pte() will return
|
||||
* non-NULL.
|
||||
*/
|
||||
fpte = pmap_pte(vm_map_pmap(&bp->b_proc->p_vmspace->vm_map), faddr);
|
||||
tpte = pmap_pte(vm_map_pmap(phys_map), taddr);
|
||||
do {
|
||||
*tpte++ = *fpte++;
|
||||
len -= PAGE_SIZE;
|
||||
} while (len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the io map PTEs associated with this IO operation.
|
||||
* We also invalidate the TLB entries and restore the original b_addr.
|
||||
*/
|
||||
vunmapbuf(bp)
|
||||
register struct buf *bp;
|
||||
vunmapbuf(bp, len)
|
||||
struct buf *bp;
|
||||
vm_size_t len;
|
||||
{
|
||||
register int npf;
|
||||
register caddr_t addr = bp->b_un.b_addr;
|
||||
vm_offset_t kva;
|
||||
vm_offset_t addr, off;
|
||||
|
||||
if ((bp->b_flags & B_PHYS) == 0)
|
||||
panic("vunmapbuf");
|
||||
npf = btoc(round_page(bp->b_bcount + ((int)addr & PGOFSET)));
|
||||
kva = (vm_offset_t)((int)addr & ~PGOFSET);
|
||||
kmem_free_wakeup(phys_map, kva, ctob(npf));
|
||||
bp->b_un.b_addr = bp->b_saveaddr;
|
||||
bp->b_saveaddr = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* (Force reset the processor by invalidating the entire address space!)
|
||||
* Well, lets just hang!
|
||||
*/
|
||||
cpu_reset()
|
||||
{
|
||||
splhigh();
|
||||
while (1);
|
||||
addr = trunc_page(bp->b_data);
|
||||
off = (vm_offset_t)bp->b_data - addr;
|
||||
len = round_page(off + len);
|
||||
kmem_free_wakeup(phys_map, addr, len);
|
||||
bp->b_data = bp->b_saveaddr;
|
||||
bp->b_saveaddr = 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue