* Copyright (c) 1988 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
* @(#)trap.c 7.10 (Berkeley) %G%
#include "../tahoe/trap.h"
#define USER 040 /* user-mode flag added to type */
"Reserved addressing mode", /* T_RESADFLT */
"Privileged instruction", /* T_PRIVINFLT */
"Reserved operand", /* T_RESOPFLT */
"Breakpoint", /* T_BPTFLT */
"Kernel call", /* T_SYSCALL */
"Arithmetic trap", /* T_ARITHTRAP */
"System forced exception", /* T_ASTFLT */
"Segmentation fault", /* T_SEGFLT */
"Protection fault", /* T_PROTFLT */
"Trace trap", /* T_TRCTRAP */
"Page fault", /* T_PAGEFLT */
"Page table fault", /* T_TABLEFLT */
"Alignment fault", /* T_ALIGNFLT */
"Kernel stack not valid", /* T_KSPNOTVAL */
"Bus error", /* T_BUSERR */
"Kernel debugger request", /* T_KDBTRAP */
int TRAP_TYPES
= sizeof (trap_type
) / sizeof (trap_type
[0]);
* Called from the trap handler when a processor trap occurs.
trap(sp
, type
, hfs
, accmst
, acclst
, dbl
, code
, pc
, psl
)
unsigned type
, code
; /* kdb assumes these are *not* registers */
int r0
, r1
; /* must reserve space */
register int *locr0
= ((int *)&psl
)-PS
;
r0
= 0; r0
= r0
; r1
= 0; r1
= r1
;
if (USERMODE(locr0
[PS
])) {
printf("trap type %d, code = %x, pc = %x\n", type
, code
, pc
);
if (type
< TRAP_TYPES
&& trap_type
[type
])
case T_PROTFLT
+ USER
: /* protection fault */
case T_PRIVINFLT
+ USER
: /* privileged instruction fault */
case T_RESADFLT
+ USER
: /* reserved addressing fault */
case T_RESOPFLT
+ USER
: /* resereved operand fault */
case T_ALIGNFLT
+ USER
: /* unaligned data fault */
case T_ASTFLT
+ USER
: /* Allow process switch */
if ((u
.u_procp
->p_flag
& SOWEUPC
) && u
.u_prof
.pr_scale
) {
addupc(pc
, &u
.u_prof
, 1);
u
.u_procp
->p_flag
&= ~SOWEUPC
;
* If the user SP is above the stack segment,
* grow the stack automatically.
if (grow((unsigned)locr0
[SP
]) || grow(code
))
case T_TABLEFLT
: /* allow page table faults in kernel */
case T_TABLEFLT
+ USER
: /* page table fault */
case T_PAGEFLT
: /* allow page faults in kernel mode */
case T_PAGEFLT
+ USER
: /* page fault */
case T_BPTFLT
+ USER
: /* bpt instruction fault */
case T_TRCTRAP
+ USER
: /* trace trap */
/* THIS CODE IS BOGUS- delete? (KSP not valid is unrecoverable)
And what does KSPNOTVAL in user-mode mean? */
* For T_KSPNOTVAL and T_BUSERR, can not allow spl to
* drop to 0 as clock could go off and we would end up
* doing an rei to the interrupt stack at ipl 0 (a
* reserved operand fault). Instead, we allow psignal
* to post an ast, then return to user mode where we
* will reenter the kernel on the kernel's stack and
* can then service the signal.
printf("pid %d: ksp not valid\n", u
.u_procp
->p_pid
);
panic("ksp not valid - 2");
/* must insure valid kernel stack pointer? */
psignal(u
.u_procp
, SIGKILL
);
* 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(locr0
[PC
], &u
.u_prof
, ticks
);
* Called from locore when a system call occurs
syscall(sp
, type
, hfs
, accmst
, acclst
, dbl
, code
, pc
, psl
)
int r0
, r1
; /* must reserve space */
register int *locr0
= ((int *)&psl
)-PS
;
register struct sysent
*callp
;
register struct proc
*p
= u
.u_procp
;
r0
= 0; r0
= r0
; r1
= 0; r1
= r1
;
if (!USERMODE(locr0
[PS
]))
params
= (caddr_t
)locr0
[FP
] + NBPW
;
* Try to reconstruct pc, assuming code
* is an immediate constant
opc
= pc
- 2; /* short literal */
opc
--; /* byte immediate */
opc
--; /* word immediate */
opc
-= 2; /* long immediate */
if (code
== 0) { /* indir */
callp
= &sysent
[0]; /* indir (illegal) */
if ((i
= callp
->sy_narg
* sizeof (int)) &&
(error
= copyin(params
, (caddr_t
)&args
, (u_int
)i
)) != 0) {
locr0
[PS
] |= 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
);
error
= (*callp
->sy_call
)(u
.u_procp
, &args
, rval
);
else if (error
!= EJUSTRETURN
) {
locr0
[PS
] |= PSL_C
; /* carry bit */
locr0
[PS
] &= ~PSL_C
; /* clear 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 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(locr0
[PC
], &u
.u_prof
, ticks
);
if (KTRPOINT(p
, KTR_SYSRET
))
ktrsysret(p
->p_tracep
, code
, error
, rval
[0]);