* Copyright (c) 1988 University of Utah.
* Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* the Systems Programming Group of the University of Utah Computer
* %sccs.include.redist.c%
* from: Utah $Hdr: trap.c 1.32 91/04/06$
* @(#)trap.c 7.13 (Berkeley) %G%
#include "../include/psl.h"
#include "../include/trap.h"
#include "../include/cpu.h"
#include "../include/reg.h"
#include "../include/mtpr.h"
#include "../hpux/hpux.h"
#define USER 040 /* user-mode flag added to type */
#define TRAP_TYPES (sizeof trap_type / sizeof trap_type[0])
* Size of various exception stack frames (minus the standard 8 bytes)
FMT0SIZE
, /* type 0 - normal (68020/030/040) */
FMT1SIZE
, /* type 1 - throwaway (68020/030/040) */
FMT2SIZE
, /* type 2 - normal 6-word (68020/030/040) */
-1, /* type 3 - FP post-instruction (68040) */
-1, -1, -1, /* type 4-6 - undefined */
-1, /* type 7 - access error (68040) */
58, /* type 8 - bus fault (68010) */
FMT9SIZE
, /* type 9 - coprocessor mid-instruction (68020/030) */
FMTASIZE
, /* type A - short bus fault (68020/030) */
FMTBSIZE
, /* type B - long bus fault (68020/030) */
-1, -1, -1, -1 /* type C-F - undefined */
* Called from the trap handler when a processor trap occurs.
trap(type
, code
, v
, frame
)
register struct proc
*p
= curproc
;
if (USERMODE(frame
.f_sr
)) {
p
->p_regs
= frame
.f_regs
;
printf("trap type %d, code = %x, v = %x\n", type
, code
, v
);
regdump(frame
.f_regs
, 128);
if ((unsigned)type
< TRAP_TYPES
)
case T_BUSERR
: /* kernel bus error */
if (!p
->p_addr
->u_pcb
.pcb_onfault
)
* If we have arranged to catch this fault in any of the
* copy to/from user space routines, set PC to return to
* indicated location and set flag informing buserror code
* that it may need to clean up stack frame.
frame
.f_stackadj
= exframesize
[frame
.f_format
];
frame
.f_format
= frame
.f_vector
= 0;
frame
.f_pc
= (int) p
->p_addr
->u_pcb
.pcb_onfault
;
case T_BUSERR
+USER
: /* bus error */
case T_ADDRERR
+USER
: /* address error */
case T_COPERR
: /* kernel coprocessor violation */
case T_FMTERR
: /* kernel format error */
* The user has most likely trashed the RTE or FP state info
* in the stack frame of a signal handler.
printf("pid %d: kernel %s exception\n", p
->p_pid
,
type
==T_COPERR
? "coprocessor" : "format");
p
->p_sigacts
->ps_sigact
[SIGILL
] = SIG_DFL
;
ucode
= frame
.f_format
; /* XXX was ILL_RESAD_FAULT */
case T_COPERR
+USER
: /* user coprocessor violation */
/* What is a proper response here? */
case T_FPERR
+USER
: /* 68881 exceptions */
* We pass along the 68881 status register which locore stashed
* in code for us. Note that there is a possibility that the
* bit pattern of this register will conflict with one of the
* FPE_* codes defined in signal.h. Fortunately for us, the
* only such codes we use are all in the range 1-7 and the low
* 3 bits of the status register are defined as 0 so there is
case T_ILLINST
+USER
: /* illegal instruction fault */
ucode
= HPUX_ILL_ILLINST_TRAP
;
case T_PRIVINST
+USER
: /* privileged instruction fault */
ucode
= HPUX_ILL_PRIV_TRAP
;
ucode
= frame
.f_format
; /* XXX was ILL_PRIVIN_FAULT */
case T_ZERODIV
+USER
: /* Divide by zero */
ucode
= HPUX_FPE_INTDIV_TRAP
;
ucode
= frame
.f_format
; /* XXX was FPE_INTDIV_TRAP */
case T_CHKINST
+USER
: /* CHK instruction trap */
/* handled differently under hp-ux */
ucode
= HPUX_ILL_CHK_TRAP
;
ucode
= frame
.f_format
; /* XXX was FPE_SUBRNG_TRAP */
case T_TRAPVINST
+USER
: /* TRAPV instruction trap */
/* handled differently under hp-ux */
ucode
= HPUX_ILL_TRAPV_TRAP
;
ucode
= frame
.f_format
; /* XXX was FPE_INTOVF_TRAP */
* XXX: Trace traps are a nightmare.
* HP-UX uses trap #1 for breakpoints,
* KGDB uses trap #15 (for kernel breakpoints; handled elsewhere).
* HPBSD and HP-UX traps both get mapped by locore.s into T_TRACE.
* SUN 3.x traps get passed through as T_TRAP15 and are not really
case T_TRACE
: /* kernel trace trap */
case T_TRAP15
: /* SUN trace trap */
case T_TRACE
+USER
: /* user trace trap */
case T_TRAP15
+USER
: /* SUN user trace trap */
case T_ASTFLT
: /* system async trap, cannot happen */
case T_ASTFLT
+USER
: /* user async trap */
* We check for software interrupts first. This is because
* they are at a higher level than ASTs, and on a VAX would
* interrupt the AST. We assume that if we are processing
* an AST that we must be at IPL0 so we don't bother to
* check. Note that we ensure that we are at least at SIR
* IPL while processing the SIR.
case T_SSIR
: /* software interrupt */
softclock((caddr_t
)frame
.f_pc
, (int)frame
.f_sr
);
* If this was not an AST trap, we are all done.
if (type
!= T_ASTFLT
+USER
) {
if ((p
->p_flag
&SOWEUPC
) && p
->p_stats
->p_prof
.pr_scale
) {
addupc(frame
.f_pc
, &p
->p_stats
->p_prof
, 1);
case T_MMUFLT
: /* kernel mode page fault */
case T_MMUFLT
+USER
: /* page fault */
register struct vmspace
*vm
= p
->p_vmspace
;
extern vm_map_t kernel_map
;
* It is only a kernel address space fault iff:
* 1. (type & USER) == 0 and
* 2. pcb_onfault not set or
* 3. pcb_onfault set but supervisor space data fault
* The last can occur during an exec() copyin where the
* argument space is lazy-allocated.
(!p
->p_addr
->u_pcb
.pcb_onfault
||
(code
& (SSW_DF
|FC_SUPERD
)) == (SSW_DF
|FC_SUPERD
)))
if ((code
& (SSW_DF
|SSW_RW
)) == SSW_DF
) /* what about RMW? */
ftype
= VM_PROT_READ
| VM_PROT_WRITE
;
va
= trunc_page((vm_offset_t
)v
);
if (map
== kernel_map
&& va
== 0) {
printf("trap: bad kernel access at %x\n", v
);
rv
= vm_fault(map
, va
, ftype
, FALSE
);
* If this was a stack access we keep track of the maximum
* accessed stack size. Also, if vm_fault gets a protection
* failure it is due to accessing the stack region outside
* the current limit and we need to reflect that as an access
if ((caddr_t
)va
>= vm
->vm_maxsaddr
&& map
!= kernel_map
) {
if (rv
== KERN_SUCCESS
) {
nss
= clrnd(btoc(USRSTACK
-(unsigned)va
));
} else if (rv
== KERN_PROTECTION_FAILURE
)
rv
= KERN_INVALID_ADDRESS
;
if (rv
== KERN_SUCCESS
) {
if (p
->p_addr
->u_pcb
.pcb_onfault
)
printf("vm_fault(%x, %x, %x, 0) -> %x\n",
printf(" type %x, code [mmu,,ssw]: %x\n",
i
= (rv
== KERN_PROTECTION_FAILURE
) ? SIGBUS
: SIGSEGV
;
* 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
.f_pc
, &p
->p_stats
->p_prof
,
addupc(frame
.f_pc
, &p
->p_stats
->p_prof
, ticks
);
* Called from the trap handler when a system call occurs
register struct sysent
*callp
;
register struct proc
*p
= curproc
;
extern struct sysent hpuxsysent
[];
extern int hpuxnsysent
, notimp();
if (!USERMODE(frame
.f_sr
))
p
->p_regs
= frame
.f_regs
;
params
= (caddr_t
)frame
.f_regs
[SP
] + NBPW
;
if (code
== 0) { /* indir */
callp
= &systab
[0]; /* indir (illegal) */
if ((i
= callp
->sy_narg
* sizeof (int)) &&
(error
= copyin(params
, (caddr_t
)&args
, (u_int
)i
))) {
error
= bsdtohpuxerrno(error
);
frame
.f_regs
[D0
] = error
;
frame
.f_sr
|= PSL_C
; /* carry bit */
if (KTRPOINT(p
, KTR_SYSCALL
))
ktrsyscall(p
->p_tracep
, code
, callp
->sy_narg
, args
.i
);
if (KTRPOINT(p
, KTR_SYSCALL
))
ktrsyscall(p
->p_tracep
, code
, callp
->sy_narg
, args
.i
);
rval
[1] = frame
.f_regs
[D1
];
if (callp
->sy_call
== notimp
)
error
= notimp(p
, args
.i
, rval
, code
, callp
->sy_narg
);
error
= (*callp
->sy_call
)(p
, &args
, rval
);
else if (error
!= EJUSTRETURN
) {
error
= bsdtohpuxerrno(error
);
frame
.f_regs
[D0
] = error
;
frame
.f_sr
|= PSL_C
; /* carry bit */
frame
.f_regs
[D0
] = rval
[0];
frame
.f_regs
[D1
] = rval
[1];
/* 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
.f_pc
, &p
->p_stats
->p_prof
,
addupc(frame
.f_pc
, &p
->p_stats
->p_prof
, ticks
);
if (KTRPOINT(p
, KTR_SYSRET
))
ktrsysret(p
->p_tracep
, code
, error
, rval
[0]);