651 lines
14 KiB
C
651 lines
14 KiB
C
/******************************************************************************
|
|
*******************************************************************************
|
|
|
|
W E G A - Quelle (C) ZFT/KEAW Abt. Basissoftware - 1985
|
|
|
|
KERN 3.2 Modul: trap.c
|
|
|
|
Bearbeiter: P. Hoge
|
|
Datum: 26.9.88
|
|
Version: 1.3
|
|
|
|
*******************************************************************************
|
|
|
|
Die nmint Routine ist abhaengig von der Hardware
|
|
|
|
Einbinden in LIB1:
|
|
chkout trap.c
|
|
scc -O -c trap.c
|
|
ar r LIB1 trap.o
|
|
(cp LIB1 /usr/sys/sys/LIB1)
|
|
|
|
*******************************************************************************
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/state.h>
|
|
#include <sys/sysinfo.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/callo.h>
|
|
#include <sys/mmu.h>
|
|
#include <sys/s.out.h>
|
|
#include <sys/dir.h>
|
|
#include <sys/user.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/text.h>
|
|
|
|
#define SCHMAG 8/10
|
|
|
|
|
|
#define sreg state->s_reg
|
|
#define eventid state->s_eventid
|
|
#define ps state->s_ps
|
|
#define pcseg state->s_pcseg
|
|
#define pc state->s_pc
|
|
|
|
extern long scfunc();
|
|
extern int Nproc;
|
|
extern long nofault;
|
|
extern int last_int_serv;
|
|
extern int console;
|
|
extern long lifetime;
|
|
extern struct proc *cpu2_pproc;
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/*
|
|
*evntentry
|
|
* Eintritt in die Interrupt oder Trap Rountine. Diese Routine muss
|
|
* bei allen Traps und Interrupts am Anfang durchlaufen werden
|
|
* (realisiert in event.s). Falls User Mode: State Pointer in User Struktur
|
|
* eintragen und Prozess Systemzeit merken
|
|
*/
|
|
/*---------------------------------------------------------------------------*/
|
|
evntentry(state)
|
|
register struct state *state;
|
|
{
|
|
if (SYSMODE(ps))
|
|
return;
|
|
else {
|
|
u.u_syst = u.u_stime;
|
|
u.u_state = state;
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/*
|
|
*uniminstr
|
|
* Trap unimlementierte Instruction
|
|
* Dieser Trap tritt auf, wenn eine EPU Instruction auftriit und keine
|
|
* EPU vorhanden oder im FCW zugelassen ist.
|
|
* In den User Programmen koennen Instruction's fuer die Floating Point EPU
|
|
* enthalten sein, die zum Aufruf der Floating Point Emulator Software
|
|
* fuehren. EPU Instruction's im Kern sind nicht zugelassen und bewirken
|
|
* Panic
|
|
*/
|
|
/*---------------------------------------------------------------------------*/
|
|
uniminstr(state)
|
|
register struct state *state;
|
|
{
|
|
register rc;
|
|
|
|
ps &= FCWBITS;
|
|
ps |= EPUBIT;
|
|
if (SYSMODE(ps)) {
|
|
prstate(state);
|
|
panic("EPU inst.");
|
|
}
|
|
evi();
|
|
rc = fpepu(state, &u.u_fpstate);
|
|
if (rc & 0x00ff)
|
|
psignal (u.u_procp, SIGSEG); /* segment violation */
|
|
if (rc & 0xFF00)
|
|
psignal (u.u_procp, SIGFPE); /* floating point exception */
|
|
if (u.u_fpflag & FPSTEP)
|
|
psignal (u.u_procp, SIGTRAP); /* trace */
|
|
|
|
u.u_fpflag = 0;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/*
|
|
*privinstr
|
|
* Trap priviligierte Instruction
|
|
* tritt auf, wenn eine priviligierte U8000 Instruction im User Mode
|
|
* abgearbeitet werden soll.
|
|
* Im System Mode tritt dieser Trap nicht auf, das Programm muss auf
|
|
* anderen unzulaessigen Wegen in diese Routine gelaufen sein, es
|
|
* erfolgt Panic
|
|
*/
|
|
/*---------------------------------------------------------------------------*/
|
|
privinstr(state)
|
|
register struct state *state;
|
|
{
|
|
ps &= FCWBITS;
|
|
ps |= TRPBIT;
|
|
if (SYSMODE(ps)) {
|
|
prstate(state);
|
|
panic ("Privileged inst.");
|
|
}
|
|
evi();
|
|
psignal (u.u_procp, SIGILL); /* illegal instruction */
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/*
|
|
*syscall
|
|
* Trap System Call
|
|
* Ueber diesen Trap wird der gewuenschte System Call aufgerufen und
|
|
* ausgefuehrt. Die CPU geht in den System Mode
|
|
* Die Tabelle der Pointer zu den System Call Funktionen befindet sich
|
|
* in sysent.c. Der Pointer zur gewuenschten Funktion wird in
|
|
* scfunc (machdep.c) gesetzt.
|
|
*/
|
|
/*---------------------------------------------------------------------------*/
|
|
syscall(state)
|
|
register struct state *state;
|
|
{
|
|
typedef int (*call)();
|
|
call sy_call;
|
|
|
|
ps &= FCWBITS;
|
|
ps |= TRPBIT;
|
|
sysinfo.syscall++;
|
|
evi();
|
|
if (SYSMODE(ps)) {
|
|
if (debug(state))
|
|
return;
|
|
panic ("Kernel syscall");
|
|
}
|
|
u.u_deverr = 0;
|
|
u.u_error = 0;
|
|
ps &= ~EBIT;
|
|
sy_call = (call)scfunc(state);
|
|
u.u_dirp.left = u.u_arg[0];
|
|
u.u_dirp.right = u.u_arg[1];
|
|
u.u_r.r_val1 = sreg[RETRLO];
|
|
u.u_r.r_val2 = sreg[RETRHI];
|
|
u.u_ap = u.u_arg;
|
|
if (save(u.u_qsav)) {
|
|
setscr();
|
|
if (u.u_error == 0)
|
|
u.u_error = EINTR;
|
|
}
|
|
else
|
|
sy_call();
|
|
|
|
if (u.u_error) {
|
|
ps |= EBIT;
|
|
sreg[RETRLO] = u.u_error;
|
|
sreg[RETRHI] = u.u_deverr;
|
|
}
|
|
else {
|
|
sreg[RETRLO] = u.u_r.r_val1;
|
|
sreg[RETRHI] = u.u_r.r_val2;
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/*
|
|
*segvio
|
|
* Segment Trap von einer MMU
|
|
* tritt der Trap im System Mode auf, erfolgt Panic. Ausnahme: Zugriff auf
|
|
* physische Adresse mit fuiword, fu...., suiword, su...., copyiin,
|
|
* copy.... in mch.s und im EPU Mode.
|
|
* Liegt User Mode und Stackueberlauf vor, wird der letzte Befehl
|
|
* rueckgaengig gemacht (in backup, machdep.c) und der Stack fuer den
|
|
* Prozess vergroessert (in grow).
|
|
* Liegt User Mode und keine Stackverletzung vor, wird das Signal
|
|
* Segmentation violation an den Prozess gesendet
|
|
*/
|
|
/*---------------------------------------------------------------------------*/
|
|
segvio(state)
|
|
register struct state *state;
|
|
{
|
|
ps &= FCWBITS;
|
|
ps |= TRPBIT;
|
|
if (SYSMODE(ps)) {
|
|
if ((u.u_state->s_ps & EPUBIT))
|
|
;
|
|
else {
|
|
if (nofault == 0) {
|
|
prstate(state);
|
|
prtmmu(state);
|
|
resmmu();
|
|
panic ("Kernel seg. violation");
|
|
}
|
|
else {
|
|
resmmu();
|
|
pcseg = hiword(nofault);
|
|
pc = loword(nofault);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if (backup(state) == 0) {
|
|
resmmu();
|
|
if (grow (u.u_state->s_sp)) {
|
|
ps &= ~TRPBIT;
|
|
if (SYSMODE(ps)) {
|
|
mapustk();
|
|
return;
|
|
}
|
|
evi();
|
|
return;
|
|
}
|
|
}
|
|
if (SYSMODE(ps)) {
|
|
if (nofault == 0) {
|
|
prstate(state);
|
|
prtmmu(state);
|
|
resmmu();
|
|
prstack(state);
|
|
panic ("Kernel/fp seg. violation");
|
|
}
|
|
else {
|
|
resmmu();
|
|
pcseg = hiword(nofault);
|
|
pc = loword(nofault);
|
|
return;
|
|
}
|
|
} else {
|
|
evi();
|
|
if (u.u_ttyd == console) {
|
|
putchar('\n');
|
|
prstate(state);
|
|
prtmmu(state);
|
|
printf("User seg. violation\n");
|
|
}
|
|
resmmu();
|
|
psignal(u.u_procp, SIGSEG);
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/*
|
|
*nmint
|
|
* Nichtmaskierter Interrupt
|
|
* Je nach Implementation koennen ein oder mehrere NMI Quellen vorhanden
|
|
* sein:
|
|
* - manuell (Taste)
|
|
* - Paritaetsfehler RAM
|
|
* - Spannungsausfall
|
|
* - Paritaetsfehler RAM 2. CPU
|
|
* Die Unterscheidung erfolgt ueber Event Identifier.
|
|
* Bei manuellem NMI werden Register und Stackinhalt auf der Konsole
|
|
* ausgegeben und das unterbrochene Programm fortgesetzt. Bei Paritaets-
|
|
* fehler erfolgt Panic, bei Spannungsausfall gibt sich der Rechner per
|
|
* Software selbst ein Reset um noch groesseren Schaden zu vermeiden.
|
|
* Bei Paritaetsfehler und Spannungsausfall erfolgt kein Update der Platte,
|
|
* Platte kann inkonsistent werden !
|
|
*/
|
|
/*---------------------------------------------------------------------------*/
|
|
nmint(state)
|
|
register struct state *state;
|
|
{
|
|
register unsigned scr;
|
|
|
|
printf ("NMI ");
|
|
switch (eventid & 0x0007) {
|
|
|
|
case 0x0001:
|
|
printf ("(manual)\n");
|
|
prstate (state);
|
|
debug(state);
|
|
break;
|
|
|
|
case 0x0002:
|
|
printf ("(power fail)\n");
|
|
in(0xffe9); /* Soft-Reset */
|
|
break;
|
|
|
|
case 0x0004:
|
|
printf ("(memory)\n");
|
|
if (SYSMODE(ps))
|
|
panic ("parity");
|
|
else {
|
|
psignal (u.u_procp, SIGBUS);
|
|
scr = inb(SCR);
|
|
outb(SCR, scr&0xf7);
|
|
outb(SCR, scr);
|
|
}
|
|
break;
|
|
/*
|
|
case 0x0007:
|
|
*/
|
|
default:
|
|
out(0xff1f, 0xfeff); /* cpu2 reset */
|
|
printf ("(memory cpu2)\n");
|
|
if (cpu2_pproc != NULL)
|
|
psignal (cpu2_pproc, SIGINT);
|
|
scr = inb(SCR);
|
|
outb(SCR, scr&0xf7);
|
|
outb(SCR, scr);
|
|
break;
|
|
/*
|
|
default:
|
|
printf ("(unknown source)\n");
|
|
*/
|
|
}
|
|
evi();
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/*
|
|
*nvi
|
|
* Nichtvektorisierter Interrupt
|
|
* Eine NVI Quelle ist nicht vorgesehen, es erfolgt Ausgabe der
|
|
* U8000 Register und Panic
|
|
*/
|
|
/*---------------------------------------------------------------------------*/
|
|
nvint(state)
|
|
register struct state *state;
|
|
{
|
|
prstate (state);
|
|
panic ("NVI");
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/*
|
|
*unexint
|
|
* nichtvorhandene vektorisierte Interrupts
|
|
* Tritt ein VI mit einem nicht im System vorhandenen Vektor auf,
|
|
* werden die Register ausgegeben und es erfolgt Panic
|
|
*/
|
|
/*---------------------------------------------------------------------------*/
|
|
unexint(state)
|
|
register struct state *state;
|
|
{
|
|
last_int_serv = UNEXINT;
|
|
prstate (state);
|
|
panic ("Unexpected VI");
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/*spurint
|
|
* nichtvorhandene vektorisierte Interrupts
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
spurint()
|
|
{
|
|
printf("WARNING: spurious int\n");
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/*
|
|
*stepint
|
|
* VI fuer die Step (Trace) Funktion
|
|
* Dieser Interrupt dient der schrittweisen Abarbeitung von zu testenden
|
|
* Programmen. Dieser Interrupt wird in der Procedure GO_INT in event.s
|
|
* aktiviert.
|
|
*/
|
|
/*---------------------------------------------------------------------------*/
|
|
stepint(state)
|
|
register struct state *state;
|
|
{
|
|
register struct state *u_state;
|
|
|
|
last_int_serv = STEPINT;
|
|
resstep();
|
|
evi();
|
|
u_state = u.u_state;
|
|
if (SYSMODE(ps)) {
|
|
if (u_state->s_ps & TRPBIT) {
|
|
u_state->s_ps &= ~TBIT;
|
|
psignal (u.u_procp, SIGTRAP);
|
|
}
|
|
else {
|
|
if (u_state->s_ps & EPUBIT)
|
|
u.u_fpflag |= FPSTEP;
|
|
else {
|
|
if (SYSMODE(ps))
|
|
debug(state);
|
|
u_state->s_ps |= TBIT;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
u_state->s_ps &= ~TBIT;
|
|
psignal (u.u_procp, SIGTRAP);
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/*
|
|
*profint
|
|
*/
|
|
/*---------------------------------------------------------------------------*/
|
|
profint()
|
|
{
|
|
last_int_serv = PROFINT;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/*
|
|
*clokint
|
|
* Clock Interrupt Service Routine
|
|
* Aufgaben bei jedem Int:
|
|
* reti an Interrupt Quelle
|
|
* Realisierung von Callouts
|
|
* Timeout Zeiten decrementieren
|
|
* bei abgelaufenen Zeiten Callout Routinen ausfuehren
|
|
* Laufzeit des aktuellen Prozesses unterteilt in User
|
|
* und System Zeit incrementieren
|
|
* Profile incrementieren
|
|
* Systemzeit (und Datum) incrementieren
|
|
*
|
|
* jede Sekunde:
|
|
* Prozesswechsel anfordern
|
|
* Sekundenprozesse wecken
|
|
* Alarmzeiten der Prozesse decrementieren, bei Ablauf Alarm
|
|
* Signalsenden
|
|
* Prozess Prioritaeten neu berechnen
|
|
* Scheduler aktivieren, falls erforderlich
|
|
*/
|
|
/*---------------------------------------------------------------------------*/
|
|
clokint(state)
|
|
struct state *state;
|
|
{
|
|
register struct callo *p1, *p2;
|
|
register a;
|
|
extern unsigned waitloc;
|
|
|
|
last_int_serv = CLOCKINT;
|
|
clkreti();
|
|
lifetime++;
|
|
|
|
/*
|
|
* callouts (timeouts)
|
|
* wenn keine vorhanden, schnell weiter
|
|
* sonst erste Zeit aktualisieren
|
|
*/
|
|
|
|
if(callout[0].c_func == NULL)
|
|
goto out;
|
|
p2 = &callout[0];
|
|
while(p2->c_time<=0 && p2->c_func!=NULL)
|
|
p2++;
|
|
p2->c_time--;
|
|
|
|
/*
|
|
* callout Routinen bei abgelaufener Zeit ausfuehren
|
|
* und aus Callout (Timeout) Tabelle streichen
|
|
*/
|
|
|
|
if(callout[0].c_time <= 0) {
|
|
p1 = &callout[0];
|
|
while(p1->c_func != 0 && p1->c_time <= 0) {
|
|
(*p1->c_func)(p1->c_arg);
|
|
p1++;
|
|
}
|
|
p2 = &callout[0];
|
|
while(p2->c_func = p1->c_func) {
|
|
p2->c_time = p1->c_time;
|
|
p2->c_arg = p1->c_arg;
|
|
p1++;
|
|
p2++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Laufzeit aktueller Prozess incrementieren
|
|
* Profile
|
|
* Systemzeit und Datum
|
|
*/
|
|
|
|
out:
|
|
if (SYSMODE(ps)) {
|
|
u.u_stime++;
|
|
if ((((long)((pcseg&MASKSEG)) <<16) | (long)pc) != (long)&waitloc) {
|
|
a = CPU_IDLE;
|
|
if (syswait.iowait)
|
|
sysinfo.wait[W_IO]++;
|
|
if (syswait.swap)
|
|
sysinfo.wait[W_SWAP]++;
|
|
if (syswait.physio)
|
|
sysinfo.wait[W_PIO]++;
|
|
}
|
|
else
|
|
a = CPU_KERNAL;
|
|
} else {
|
|
u.u_utime++;
|
|
a = CPU_USER;
|
|
if(u.u_prof[0].pr_scale)
|
|
aprof(state, 1);
|
|
}
|
|
sysinfo.cpu[a] += 1;
|
|
clock2(); /* Fortsetzung */
|
|
}
|
|
|
|
/* Fortsetzung von clokint */
|
|
|
|
clock2()
|
|
{
|
|
register struct proc *pp;
|
|
register a;
|
|
|
|
pp = u.u_procp;
|
|
if(pp->p_stat == SRUN) {
|
|
u.u_mem += (unsigned)pp->p_size;
|
|
if (pp->p_textp) {
|
|
a = pp->p_textp->x_ccount;
|
|
if (a == 0)
|
|
a++;
|
|
u.u_mem += pp->p_textp->x_size / a;
|
|
}
|
|
}
|
|
if(++pp->p_cpu == 0)
|
|
pp->p_cpu--;
|
|
if(++lbolt >= HZ) {
|
|
lbolt -= HZ;
|
|
time++;
|
|
evi();
|
|
|
|
/*
|
|
* Prozesswechsel fordern
|
|
* Sekundenprozesse wecken (lightning bolt time-out)
|
|
*/
|
|
|
|
runrun++;
|
|
wakeup((caddr_t)&lbolt);
|
|
|
|
/*
|
|
* Prozesszeiten incrementieren
|
|
* Alarm Funktion
|
|
* Prioritaeten neu festlegen
|
|
*/
|
|
|
|
for(pp = &proc[0]; pp < &proc[Nproc]; pp++)
|
|
if (pp->p_stat && pp->p_stat<SZOMB) {
|
|
if(pp->p_time != 127)
|
|
pp->p_time++;
|
|
if(pp->p_clktim)
|
|
if(--pp->p_clktim == 0)
|
|
psignal(pp, SIGALRM);
|
|
a = (pp->p_cpu & 0377)*SCHMAG + pp->p_nice - NZERO;
|
|
if(a < 0)
|
|
a = 0;
|
|
if(a > 255)
|
|
a = 255;
|
|
pp->p_cpu = a;
|
|
if(pp->p_pri >= PUSER)
|
|
setpri(pp);
|
|
}
|
|
|
|
/* Scheduler aktivieren */
|
|
|
|
if(runin!=0) {
|
|
runin = 0;
|
|
wakeup((caddr_t)&runin);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/*
|
|
*evntret
|
|
* Austritt aus allen Interrupts und Traps
|
|
* wenn Signal an aktuellen Prozess vorhanden, an Prozess senden
|
|
* Prioritaet des aktuellen Prozesses neu festlegen
|
|
* wenn Prozesswechsel gefordert, Prozesswechsel ausfuehren
|
|
* Profile des aktuellen Prozesses (korrigieren)
|
|
*/
|
|
/*---------------------------------------------------------------------------*/
|
|
evntret(state)
|
|
register struct state *state;
|
|
{
|
|
if (SYSMODE(ps))
|
|
return;
|
|
else {
|
|
evi();
|
|
if (u.u_procp->p_sig) {
|
|
if (issig())
|
|
psig();
|
|
}
|
|
if (runrun) {
|
|
curpri = setpri(u.u_procp);
|
|
if (runrun) {
|
|
sysinfo.preempt++;
|
|
qswtch();
|
|
}
|
|
}
|
|
setscr();
|
|
dvi();
|
|
if (u.u_segmented)
|
|
ps |= SEGFCW;
|
|
else
|
|
ps &= ~SEGFCW;
|
|
|
|
if (u.u_prof[0].pr_scale)
|
|
aprof(state, (int)(u.u_stime-u.u_syst));
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/*
|
|
*aprof
|
|
* fuer profiling
|
|
* Die Routine war ursprueglich in clokint und evntret enthalten
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
aprof(state, time)
|
|
register struct state *state;
|
|
register time;
|
|
{
|
|
register unsigned seg;
|
|
register unsigned i;
|
|
|
|
i = 0;
|
|
if (u.u_segmented) {
|
|
seg = (pcseg & MASKSEG) >> 8;
|
|
for (;; i++) {
|
|
if (i >= u.u_nprof)
|
|
return;
|
|
if ((unsigned char)u.u_pr_segno[i] == seg)
|
|
break;
|
|
}
|
|
}
|
|
addupc (pc, pcseg, &u.u_prof[i], time);
|
|
}
|