* Copyright (c) 1990 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* the University of Utah, and William Jolitz.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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
* @(#)trap.c 7.4 (Berkeley) 5/13/91
static char rcsid
[] = "$Header: /usr/bill/working/sys/i386/i386/RCS/trap.c,v 1.2 92/01/21 14:22:13 william Exp $";
* 386 Trap and System call handleing
#include "machine/trap.h"
* Exception, fault, and trap interface to BSD kernel. This
* common code is called from assembly language IDT gate entry
* 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.
register struct proc
*p
= curproc
;
int ucode
, type
, code
, eva
;
frame
.tf_eflags
&= ~PSL_NT
; /* clear nested trap XXX */
if (curpcb
&& curpcb
->pcb_onfault
) {
if (frame
.tf_trapno
== T_BPTFLT
|| frame
.tf_trapno
== T_TRCTRAP
)
if (kdb_trap (type
, 0, &frame
))
/*pg("trap type %d code = %x eip = %x cs = %x eva = %x esp %x",
frame.tf_trapno, frame.tf_err, frame.tf_eip,
frame.tf_cs, rcr2(), frame.tf_esp);*/
if(curpcb
== 0 || curproc
== 0) goto we_re_toast
;
if (curpcb
->pcb_onfault
&& frame
.tf_trapno
!= 0xc) {
frame
.tf_eip
= (int)curpcb
->pcb_onfault
;
if (ISPL(frame
.tf_cs
) == SEL_UPL
) {
p
->p_regs
= (int *)&frame
;
curpcb
->pcb_flags
|= FM_TRAP
; /* used by sendsig */
if (kdb_trap (type
, 0, &frame
))
printf("trap type %d code = %x eip = %x cs = %x eflags = %x ",
frame
.tf_trapno
, frame
.tf_err
, frame
.tf_eip
,
frame
.tf_cs
, frame
.tf_eflags
);
printf("cr2 %x cpl %x\n", eva
, cpl
);
/* type &= ~T_USER; */ /* XXX what the hell is this */
case T_PROTFLT
|T_USER
: /* protection fault */
ucode
= code
+ BUS_SEGM_FAULT
;
case T_PRIVINFLT
|T_USER
: /* privileged instruction fault */
case T_RESADFLT
|T_USER
: /* reserved addressing fault */
case T_RESOPFLT
|T_USER
: /* reserved operand fault */
case T_FPOPFLT
|T_USER
: /* coprocessor operand fault */
case T_ASTFLT
|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);
/* if a transparent fault (due to context switch "late") */
i
= math_emulate(&frame
);
case T_PAGEFLT
: /* allow page faults in kernel mode */
if (code
& PGEX_P
) goto we_re_toast
;
case T_PAGEFLT
|T_USER
: /* page fault */
register struct vmspace
*vm
= p
->p_vmspace
;
extern vm_map_t kernel_map
;
va
= trunc_page((vm_offset_t
)eva
);
* It is only a kernel address space fault iff:
* 1. (type & T_USER) == 0 and
* 2. pcb_onfault not set or
* 3. pcb_onfault set but supervisor space fault
* The last can occur during an exec() copyin where the
* argument space is lazy-allocated.
if (type
== T_PAGEFLT
&& va
>= 0xfe000000)
ftype
= VM_PROT_READ
| VM_PROT_WRITE
;
if (map
== kernel_map
&& va
== 0) {
printf("trap: bad kernel access at %x\n", va
);
* XXX: rude hack to make stack limits "work"
if ((caddr_t
)va
>= vm
->vm_maxsaddr
&& map
!= kernel_map
nss
= clrnd(btoc((unsigned)vm
->vm_maxsaddr
+ MAXSSIZ
- (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);*/
/* check if page table is mapped, if not, fault it first */
#define pde_v(v) (PTD[((v)>>PD_SHIFT)&1023].pd_v)
v
= trunc_page(vtopte(va
));
rv
= vm_fault(map
, v
, ftype
, FALSE
);
if (rv
!= KERN_SUCCESS
) goto nogo
;
/* check if page table fault, increment wiring */
vm_map_pageable(map
, v
, round_page(v
+1), FALSE
);
rv
= vm_fault(map
, va
, ftype
, FALSE
);
if (rv
== KERN_SUCCESS
) {
* XXX: continuation of rude stack hack
va
= trunc_page(vtopte(va
));
/* for page table, increment wiring
as long as not a page table fault as well */
if (!v
&& type
!= T_PAGEFLT
)
vm_map_pageable(map
, va
, round_page(va
+1), FALSE
);
printf("vm_fault(%x, %x, %x, 0) -> %x\n",
printf(" type %x, code %x\n",
i
= (rv
== KERN_PROTECTION_FAILURE
) ? SIGBUS
: SIGSEGV
;
case T_TRCTRAP
: /* trace trap -- someone single stepping lcall's */
frame
.tf_eflags
&= ~PSL_T
;
/* Q: how do we turn it on again? */
case T_BPTFLT
|T_USER
: /* bpt instruction fault */
case T_TRCTRAP
|T_USER
: /* trace trap */
frame
.tf_eflags
&= ~PSL_T
;
/* NMI can be hooked up to a pushbutton for debugging */
printf ("NMI ... going to debugger\n");
if (kdb_trap (type
, 0, &frame
))
/* machine/parity/power fail/"kitchen sink" faults */
if(isa_nmi(code
) == 0) return;
if ((type
& T_USER
) == 0)
* 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 setrq ourselves but before we
* swtch()'ed, we might not be on the queue indicated by
p
->p_stats
->p_ru
.ru_nivcsw
++;
if (p
->p_stats
->p_prof
.pr_scale
) {
struct timeval
*tv
= &p
->p_stime
;
ticks
= ((tv
->tv_sec
- syst
.tv_sec
) * 1000 +
(tv
->tv_usec
- syst
.tv_usec
) / 1000) / (tick
/ 1000);
addupc(frame
.tf_eip
, &p
->p_stats
->p_prof
,
addupc(frame
.tf_eip
, &p
->p_stats
->p_prof
, ticks
);
curpcb
->pcb_flags
&= ~FM_TRAP
; /* used by sendsig */
* Compensate for 386 brain damage (missing URKR)
int trapwrite(unsigned addr
) {
va
= trunc_page((vm_offset_t
)addr
);
if (va
> VM_MAXUSER_ADDRESS
) return(1);
rv
= vm_fault(&curproc
->p_vmspace
->vm_map
, va
,
VM_PROT_READ
| VM_PROT_WRITE
, FALSE
);
if (rv
== KERN_SUCCESS
) return(0);
* System call request from POSIX system call gate interface to kernel.
* Like trap(), argument is call by reference.
volatile struct syscframe frame
;
register int *locr0
= ((int *)&frame
);
register struct sysent
*callp
;
register struct proc
*p
= curproc
;
r0
= 0; r0
= r0
; r1
= 0; r1
= r1
;
if (ISPL(frame
.sf_cs
) != SEL_UPL
)
curpcb
->pcb_flags
&= ~FM_TRAP
; /* used by sendsig */
p
->p_regs
= (int *)&frame
;
params
= (caddr_t
)frame
.sf_esp
+ sizeof (int) ;
* Reconstruct pc, assuming lcall $X,y is 7 bytes, as it is always.
callp
= (code
>= nsysent
) ? &sysent
[63] : &sysent
[code
];
callp
= (code
>= nsysent
) ? &sysent
[63] : &sysent
[code
];
if ((i
= callp
->sy_narg
* sizeof (int)) &&
(error
= copyin(params
, (caddr_t
)args
, (u_int
)i
))) {
frame
.sf_eflags
|= PSL_C
; /* carry bit */
if (KTRPOINT(p
, KTR_SYSCALL
))
ktrsyscall(p
->p_tracep
, code
, callp
->sy_narg
, &args
);
if (KTRPOINT(p
, KTR_SYSCALL
))
ktrsyscall(p
->p_tracep
, code
, callp
->sy_narg
, &args
);
/*pg("%d. s %d\n", p->p_pid, code);*/
error
= (*callp
->sy_call
)(p
, args
, rval
);
else if (error
!= EJUSTRETURN
) {
/*pg("error %d", error);*/
frame
.sf_eflags
|= PSL_C
; /* carry bit */
frame
.sf_eflags
&= ~PSL_C
; /* carry bit */
/* else if (error == EJUSTRETURN) */
* Reinitialize proc pointer `p' as it may be different
* if this is a child returning from fork syscall.
* 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 setrq ourselves but before we
* swtch()'ed, we might not be on the queue indicated by
p
->p_stats
->p_ru
.ru_nivcsw
++;
if (p
->p_stats
->p_prof
.pr_scale
) {
struct timeval
*tv
= &p
->p_stime
;
ticks
= ((tv
->tv_sec
- syst
.tv_sec
) * 1000 +
(tv
->tv_usec
- syst
.tv_usec
) / 1000) / (tick
/ 1000);
addupc(frame
.sf_eip
, &p
->p_stats
->p_prof
,
addupc(frame
.sf_eip
, &p
->p_stats
->p_prof
, ticks
);
if (KTRPOINT(p
, KTR_SYSRET
))
ktrsysret(p
->p_tracep
, code
, error
, rval
[0]);
{ extern int _udatasel
, _ucodesel
;
if (frame
.sf_ss
!= _udatasel
)
printf("ss %x call %d\n", frame
.sf_ss
, code
);
if ((frame
.sf_cs
&0xffff) != _ucodesel
)
printf("cs %x call %d\n", frame
.sf_cs
, code
);
if (frame
.sf_eip
> VM_MAXUSER_ADDRESS
) {
printf("eip %x call %d\n", frame
.sf_eip
, code
);