* 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.28 89/09/25$
* @(#)trap.c 7.3 (Berkeley) %G%
#include "../hpux/hpux.h"
#define USER 040 /* user-mode flag added to type */
#define TRAP_TYPES (sizeof trap_type / sizeof trap_type[0])
* Called from the trap handler when a processor trap occurs.
trap(type
, code
, v
, frame
)
register struct proc
*p
= u
.u_procp
;
if (USERMODE(frame
.f_sr
)) {
if (!panicstr
&& kgdb_trap(type
, code
, v
, &frame
))
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 (!u
.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_pc
= (int) u
.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", u
.u_procp
->p_pid
,
type
==T_COPERR
? "coprocessor" : "format");
u
.u_signal
[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 */
if (u
.u_procp
->p_flag
& SHPUX
) {
ucode
= HPUX_ILL_ILLINST_TRAP
;
case T_PRIVINST
+USER
: /* privileged instruction fault */
if (u
.u_procp
->p_flag
& SHPUX
)
ucode
= HPUX_ILL_PRIV_TRAP
;
ucode
= frame
.f_format
; /* XXX was ILL_PRIVIN_FAULT */
case T_ZERODIV
+USER
: /* Divide by zero */
if (u
.u_procp
->p_flag
& SHPUX
)
ucode
= HPUX_FPE_INTDIV_TRAP
;
ucode
= frame
.f_format
; /* XXX was FPE_INTDIV_TRAP */
case T_CHKINST
+USER
: /* CHK instruction trap */
if (u
.u_procp
->p_flag
& SHPUX
) {
/* 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 */
if (u
.u_procp
->p_flag
& SHPUX
) {
/* 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).
* 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
* supported yet. KGDB traps are also passed through as T_TRAP15
case T_TRACE
: /* kernel trace trap */
case T_TRAP15
: /* SUN (or KGDB) kernel trace trap */
if (kgdb_trap(type
, code
, v
, &frame
))
case T_TRACE
+USER
: /* user trace trap */
case T_TRAP15
+USER
: /* SUN user trace trap */
* Trap #2 is used to signal a cache flush.
* Should we also flush data cache?
if (type
== T_TRACE
+USER
&& (p
->p_flag
& SSUN
)) {
case T_AST
: /* system async trap, cannot happen */
case T_AST
+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_AST
+USER
) {
if ((u
.u_procp
->p_flag
&SOWEUPC
) && u
.u_prof
.pr_scale
) {
addupc(frame
.f_pc
, &u
.u_prof
, 1);
u
.u_procp
->p_flag
&= ~SOWEUPC
;
case T_MMUFLT
: /* kernel mode page fault */
* Could be caused by a page fault in one of the copy to/from
* user space routines. If so, we will have a catch address.
if (!u
.u_pcb
.pcb_onfault
)
case T_MMUFLT
+USER
: /* page fault */
printf("trap: T_MMUFLT pid %d, code %x, v %x, pc %x, ps %x\n",
p->p_pid, code, v, frame.f_pc, frame.f_sr);
#if defined(HP330) || defined(HP360) || defined(HP370)
* Crudely map PMMU faults into HP MMU faults.
else if (ocode
& PMMU_INV
) {
if ((ocode
& PMMU_LVLMASK
) == 2)
* RMW cycle, must load ATC by hand
else if ((code
& (SSW_DF
|SSW_RM
)) == (SSW_DF
|SSW_RM
)) {
"RMW fault at %x: MMUSR %x SSW %x\n",
v
, ocode
, code
& 0xFFFF);
* Fault with no fault bits, should indicate bad
* hardware but we see this on 340s using starbase
* sometimes (faults accessing catseye registers)
"Bad PMMU fault at %x: MMUSR %x SSW %x\n",
v
, ocode
, code
& 0xFFFF);
if (mmudebug
&& mmudebug
== p
->p_pid
)
printf("MMU %d: v%x, os%x, ns%x\n",
p
->p_pid
, v
, ocode
, ncode
);
if ((ncode
& (MMU_PTF
|MMU_PF
|MMU_WPF
|MMU_FPE
)) == 0) {
printf("T_MMUFLT with no fault bits\n");
* NOTE: we use a u_int instead of an ste since the
* current compiler generates bogus code for some
* bitfield operations (i.e. attempts to access last
* word of a page as a longword causing fault).
extern struct ste
*vtoste();
u_int
*ste
= (u_int
*)vtoste(p
, v
);
printf("MMU_PTF with sg_v, ste@%x = %x\n",
extern struct ste
*vtoste();
bste
= (u_int
*)vtoste(p
, HPMMBASEADDR(v
));
nste
= (u_int
*)vtoste(p
, v
);
if ((*bste
& SG_V
) && *nste
== SG_NV
) {
if (grow((unsigned)frame
.f_regs
[SP
]) || grow(v
))
* NOTE: WPF without PG_V is possible
* (e.g. attempt to write shared text which is paged out)
extern struct ste
*vtoste();
u_int
*ste
= (u_int
*)vtoste(p
, v
);
printf("MMU_WPF without sg_v, ste@%x = %x\n",
extern struct ste
*vtoste();
u_int
*ste
= (u_int
*)vtoste(p
, v
);
printf("MMU_PF without sg_v, ste@%x = %x\n",
if (vp
>= dptov(p
, p
->p_dsize
) &&
vp
< sptov(p
, p
->p_ssize
-1))
if (*(u_int
*)pte
& PG_V
) {
printf("MMU_PF with pg_v, pte = %x\n",
printf("T_MMUFLT: unrecognized scenerio\n");
* Since we are u.u_procp, 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
struct timeval
*tv
= &u
.u_ru
.ru_stime
;
ticks
= ((tv
->tv_sec
- syst
.tv_sec
) * 1000 +
(tv
->tv_usec
- syst
.tv_usec
) / 1000) / (tick
/ 1000);
addupc(frame
.f_pc
, &u
.u_prof
, ticks
* profscale
);
addupc(frame
.f_pc
, &u
.u_prof
, ticks
);
* Called from the trap handler when a system call occurs
register struct sysent
*callp
;
register struct proc
*p
= u
.u_procp
;
extern struct sysent hpuxsysent
[];
extern int hpuxnsysent
, notimp();
if (!USERMODE(frame
.f_sr
))
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
)u
.u_arg
, (u_int
)i
))) {
error
= bsdtohpuxerrno(error
);
frame
.f_regs
[D0
] = (u_char
) error
;
frame
.f_sr
|= PSL_C
; /* carry bit */
if (KTRPOINT(p
, KTR_SYSCALL
))
ktrsyscall(p
->p_tracep
, code
, callp
->sy_narg
);
if (KTRPOINT(p
, KTR_SYSCALL
))
ktrsyscall(p
->p_tracep
, code
, callp
->sy_narg
);
u
.u_r
.r_val2
= frame
.f_regs
[D0
];
if (callp
->sy_call
== notimp
)
error
= notimp(code
, callp
->sy_narg
);
error
= (*(callp
->sy_call
))(&u
);
error
= u
.u_error
; /* XXX */
else if (error
!= EJUSTRETURN
) {
error
= bsdtohpuxerrno(error
);
frame
.f_regs
[D0
] = (u_char
) error
;
frame
.f_sr
|= PSL_C
; /* carry bit */
frame
.f_regs
[D0
] = u
.u_r
.r_val1
;
frame
.f_regs
[D1
] = u
.u_r
.r_val2
;
/* else if (error == EJUSTRETURN) */
* Reinitialize proc pointer `p' as it may be different
* if this is a child returning from fork syscall.
* XXX the check for sigreturn ensures that we don't
* attempt to set up a call to a signal handler (sendsig) before
* we have cleaned up the stack from the last call (sigreturn).
* Allowing this seems to lock up the machine in certain scenarios.
* What should really be done is to clean up the signal handling
* so that this is not a problem.
if (code
!= SYS_sigreturn
&& (i
= CURSIG(p
)))
* Since we are u.u_procp, 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
struct timeval
*tv
= &u
.u_ru
.ru_stime
;
ticks
= ((tv
->tv_sec
- syst
.tv_sec
) * 1000 +
(tv
->tv_usec
- syst
.tv_usec
) / 1000) / (tick
/ 1000);
addupc(frame
.f_pc
, &u
.u_prof
, ticks
* profscale
);
addupc(frame
.f_pc
, &u
.u_prof
, ticks
);
if (KTRPOINT(p
, KTR_SYSRET
))
ktrsysret(p
->p_tracep
, code
);