2011-03-30 12:46:40 +00:00
|
|
|
#include "u.h"
|
|
|
|
#include "../port/lib.h"
|
|
|
|
#include "mem.h"
|
|
|
|
#include "dat.h"
|
|
|
|
#include "fns.h"
|
|
|
|
#include "ureg.h"
|
|
|
|
#include "io.h"
|
|
|
|
#include "tos.h"
|
|
|
|
#include "../port/error.h"
|
|
|
|
|
|
|
|
static Lock vctllock;
|
|
|
|
static Vctl *vctl[256];
|
|
|
|
|
|
|
|
void
|
|
|
|
hwintrinit(void)
|
|
|
|
{
|
|
|
|
i8259init();
|
|
|
|
mpicenable(0, nil); /* 8259 interrupts are routed through MPIC intr 0 */
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
hwintrenable(Vctl *v)
|
|
|
|
{
|
|
|
|
int vec, irq;
|
|
|
|
|
|
|
|
irq = v->irq;
|
|
|
|
if(BUSTYPE(v->tbdf) == BusPCI) { /* MPIC? */
|
|
|
|
if(irq > 15) {
|
|
|
|
print("intrenable: pci irq %d out of range\n", v->irq);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
vec = irq;
|
|
|
|
mpicenable(vec, v);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if(irq > MaxIrqPIC) {
|
|
|
|
print("intrenable: irq %d out of range\n", v->irq);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
vec = irq+VectorPIC;
|
|
|
|
if(i8259enable(v) == -1)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return vec;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
hwintrdisable(Vctl *v)
|
|
|
|
{
|
|
|
|
int vec, irq;
|
|
|
|
|
|
|
|
irq = v->irq;
|
|
|
|
if(BUSTYPE(v->tbdf) == BusPCI) { /* MPIC? */
|
|
|
|
if(irq > 15) {
|
|
|
|
print("intrdisable: pci irq %d out of range\n", v->irq);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
vec = irq;
|
|
|
|
mpicdisable(vec);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if(irq > MaxIrqPIC) {
|
|
|
|
print("intrdisable: irq %d out of range\n", v->irq);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
vec = irq+VectorPIC;
|
|
|
|
if(i8259disable(irq) == -1)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return vec;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
hwvecno(int irq, int tbdf)
|
|
|
|
{
|
|
|
|
if(BUSTYPE(tbdf) == BusPCI) /* MPIC? */
|
|
|
|
return irq;
|
|
|
|
else
|
|
|
|
return irq+VectorPIC;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
|
|
|
|
{
|
|
|
|
int vno;
|
|
|
|
Vctl *v;
|
|
|
|
|
|
|
|
if(f == nil){
|
|
|
|
print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n",
|
|
|
|
irq, tbdf, name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
v = xalloc(sizeof(Vctl));
|
|
|
|
v->isintr = 1;
|
|
|
|
v->irq = irq;
|
|
|
|
v->tbdf = tbdf;
|
|
|
|
v->f = f;
|
|
|
|
v->a = a;
|
|
|
|
strncpy(v->name, name, KNAMELEN-1);
|
|
|
|
v->name[KNAMELEN-1] = 0;
|
|
|
|
|
|
|
|
ilock(&vctllock);
|
|
|
|
vno = hwintrenable(v);
|
|
|
|
if(vno == -1){
|
|
|
|
iunlock(&vctllock);
|
|
|
|
print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n",
|
|
|
|
irq, tbdf, v->name);
|
|
|
|
xfree(v);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(vctl[vno]){
|
|
|
|
if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi)
|
|
|
|
panic("intrenable: handler: %s %s %#p %#p %#p %#p",
|
|
|
|
vctl[vno]->name, v->name,
|
|
|
|
vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi);
|
|
|
|
v->next = vctl[vno];
|
|
|
|
}
|
|
|
|
vctl[vno] = v;
|
|
|
|
iunlock(&vctllock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name)
|
|
|
|
{
|
|
|
|
Vctl **pv, *v;
|
|
|
|
int vno;
|
|
|
|
|
|
|
|
vno = hwvecno(irq, tbdf);
|
|
|
|
ilock(&vctllock);
|
|
|
|
pv = &vctl[vno];
|
|
|
|
while (*pv &&
|
|
|
|
((*pv)->irq != irq || (*pv)->tbdf != tbdf || (*pv)->f != f || (*pv)->a != a ||
|
|
|
|
strcmp((*pv)->name, name)))
|
|
|
|
pv = &((*pv)->next);
|
|
|
|
assert(*pv);
|
|
|
|
|
|
|
|
v = *pv;
|
|
|
|
*pv = (*pv)->next; /* Link out the entry */
|
|
|
|
|
|
|
|
if(vctl[vno] == nil)
|
|
|
|
hwintrdisable(v);
|
|
|
|
iunlock(&vctllock);
|
|
|
|
xfree(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
void syscall(Ureg*);
|
|
|
|
void noted(Ureg*, ulong);
|
|
|
|
static void _dumpstack(Ureg*);
|
|
|
|
|
|
|
|
char *excname[] =
|
|
|
|
{
|
|
|
|
"reserved 0",
|
|
|
|
"system reset",
|
|
|
|
"machine check",
|
|
|
|
"data access",
|
|
|
|
"instruction access",
|
|
|
|
"external interrupt",
|
|
|
|
"alignment",
|
|
|
|
"program exception",
|
|
|
|
"floating-point unavailable",
|
|
|
|
"decrementer",
|
|
|
|
"reserved A",
|
|
|
|
"reserved B",
|
|
|
|
"system call",
|
|
|
|
"trace trap",
|
|
|
|
"floating point assist",
|
|
|
|
"reserved F",
|
|
|
|
"reserved 10",
|
|
|
|
"reserved 11",
|
|
|
|
"reserved 12",
|
|
|
|
"instruction address breakpoint",
|
|
|
|
"system management interrupt",
|
|
|
|
};
|
|
|
|
|
|
|
|
char *fpcause[] =
|
|
|
|
{
|
|
|
|
"inexact operation",
|
|
|
|
"division by zero",
|
|
|
|
"underflow",
|
|
|
|
"overflow",
|
|
|
|
"invalid operation",
|
|
|
|
};
|
|
|
|
char *fpexcname(Ureg*, ulong, char*);
|
|
|
|
#define FPEXPMASK 0xfff80300 /* Floating exception bits in fpscr */
|
|
|
|
|
|
|
|
|
|
|
|
char *regname[]={
|
|
|
|
"CAUSE", "SRR1",
|
|
|
|
"PC", "GOK",
|
|
|
|
"LR", "CR",
|
|
|
|
"XER", "CTR",
|
|
|
|
"R0", "R1",
|
|
|
|
"R2", "R3",
|
|
|
|
"R4", "R5",
|
|
|
|
"R6", "R7",
|
|
|
|
"R8", "R9",
|
|
|
|
"R10", "R11",
|
|
|
|
"R12", "R13",
|
|
|
|
"R14", "R15",
|
|
|
|
"R16", "R17",
|
|
|
|
"R18", "R19",
|
|
|
|
"R20", "R21",
|
|
|
|
"R22", "R23",
|
|
|
|
"R24", "R25",
|
|
|
|
"R26", "R27",
|
|
|
|
"R28", "R29",
|
|
|
|
"R30", "R31",
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
trap(Ureg *ureg)
|
|
|
|
{
|
|
|
|
ulong dsisr;
|
|
|
|
int ecode, user;
|
|
|
|
char buf[ERRMAX], *s;
|
|
|
|
|
2020-12-20 21:34:41 +00:00
|
|
|
user = kenter(ureg);
|
2011-03-30 12:46:40 +00:00
|
|
|
ecode = (ureg->cause >> 8) & 0xff;
|
2015-06-13 18:21:26 +00:00
|
|
|
if((ureg->status & MSR_RI) == 0)
|
2011-03-30 12:46:40 +00:00
|
|
|
print("double fault?: ecode = %d\n", ecode);
|
|
|
|
|
|
|
|
switch(ecode) {
|
|
|
|
case CEI:
|
|
|
|
intr(ureg);
|
|
|
|
break;
|
|
|
|
case CDEC:
|
|
|
|
clockintr(ureg);
|
|
|
|
break;
|
|
|
|
case CSYSCALL:
|
|
|
|
if(!user)
|
|
|
|
panic("syscall in kernel: srr1 0x%4.4luX", ureg->srr1);
|
|
|
|
syscall(ureg);
|
|
|
|
return; /* syscall() calls notify itself, don't do it again */
|
|
|
|
case CFPU:
|
|
|
|
if(!user || up == nil) {
|
|
|
|
dumpregs(ureg);
|
|
|
|
panic("floating point in kernel");
|
|
|
|
}
|
|
|
|
switch(up->fpstate){
|
|
|
|
case FPinit:
|
|
|
|
fprestore(&initfp);
|
|
|
|
up->fpstate = FPactive;
|
|
|
|
break;
|
|
|
|
case FPinactive:
|
kernel: introduce per process FPU struct (PFPU) for more flexible machine specific fpu handling
introducing the PFPU structue which allows the machine specific
code some flexibility on how to handle the FPU process state.
for example, in the pc and pc64 kernel, the FPsave structure is
arround 512 bytes. with avx512, it could grow up to 2K. instead
of embedding that into the Proc strucutre, it is more effective
to allocate it on first use of the fpu, as most processes do not
use simd or floating point in the first place. also, the FPsave
structure has special 16 byte alignment constraint, which further
favours dynamic allocation.
this gets rid of the memmoves in pc/pc64 kernels for the aligment.
there is also devproc, which is now checking if the fpsave area
is actually valid before reading it, avoiding debuggers to see
garbage data.
the Notsave structure is gone now, as it was not used on any
machine.
2017-11-04 19:08:22 +00:00
|
|
|
fprestore(up->fpsave);
|
2011-03-30 12:46:40 +00:00
|
|
|
up->fpstate = FPactive;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
panic("fpstate");
|
|
|
|
}
|
|
|
|
ureg->srr1 |= MSR_FP;
|
|
|
|
break;
|
|
|
|
case CISI:
|
|
|
|
faultpower(ureg, ureg->pc, 1);
|
|
|
|
break;
|
|
|
|
case CDSI:
|
|
|
|
dsisr = getdsisr();
|
|
|
|
if(dsisr & BIT(6))
|
|
|
|
faultpower(ureg, getdar(), 0);
|
|
|
|
else
|
|
|
|
faultpower(ureg, getdar(), 1);
|
|
|
|
break;
|
|
|
|
case CPROG:
|
|
|
|
if(ureg->status & (1<<19))
|
|
|
|
s = "floating point exception";
|
|
|
|
else if(ureg->status & (1<<18))
|
|
|
|
s = "illegal instruction";
|
|
|
|
else if(ureg->status & (1<<17))
|
|
|
|
s = "privileged instruction";
|
|
|
|
else
|
|
|
|
s = "undefined program exception";
|
|
|
|
if(user){
|
|
|
|
spllo();
|
|
|
|
sprint(buf, "sys: trap: %s", s);
|
|
|
|
postnote(up, 1, buf, NDebug);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
dumpregs(ureg);
|
|
|
|
panic(s);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if(ecode < nelem(excname) && user){
|
|
|
|
spllo();
|
|
|
|
sprint(buf, "sys: trap: %s", excname[ecode]);
|
|
|
|
postnote(up, 1, buf, NDebug);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
dumpregs(ureg);
|
|
|
|
if(ecode < nelem(excname))
|
|
|
|
panic("%s", excname[ecode]);
|
|
|
|
panic("unknown trap/intr: %d", ecode);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* restoreureg must execute at high IPL */
|
|
|
|
splhi();
|
|
|
|
|
|
|
|
/* delaysched set because we held a lock or because our quantum ended */
|
|
|
|
if(up && up->delaysched && ecode == CDEC){
|
|
|
|
sched();
|
|
|
|
splhi();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(user) {
|
|
|
|
notify(ureg);
|
|
|
|
if(up->fpstate == FPinactive)
|
|
|
|
ureg->srr1 &= ~MSR_FP;
|
|
|
|
kexit(ureg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
faultpower(Ureg *ureg, ulong addr, int read)
|
|
|
|
{
|
|
|
|
int user, insyscall, n;
|
|
|
|
char buf[ERRMAX];
|
|
|
|
|
|
|
|
user = (ureg->srr1 & MSR_PR) != 0;
|
|
|
|
insyscall = up->insyscall;
|
|
|
|
up->insyscall = 1;
|
2019-08-27 01:47:18 +00:00
|
|
|
n = fault(addr, ureg->pc, read);
|
2011-03-30 12:46:40 +00:00
|
|
|
if(n < 0){
|
|
|
|
if(!user){
|
|
|
|
dumpregs(ureg);
|
|
|
|
panic("fault: 0x%lux", addr);
|
|
|
|
}
|
|
|
|
sprint(buf, "sys: trap: fault %s addr=0x%lux", read? "read" : "write", addr);
|
|
|
|
postnote(up, 1, buf, NDebug);
|
|
|
|
}
|
|
|
|
up->insyscall = insyscall;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sethvec(int v, void (*r)(void))
|
|
|
|
{
|
|
|
|
ulong *vp, pa, o;
|
|
|
|
|
|
|
|
vp = KADDR(v);
|
|
|
|
vp[0] = 0x7c1043a6; /* MOVW R0, SPR(SPRG0) */
|
|
|
|
vp[1] = 0x7c0802a6; /* MOVW LR, R0 */
|
|
|
|
vp[2] = 0x7c1243a6; /* MOVW R0, SPR(SPRG2) */
|
|
|
|
pa = PADDR(r);
|
|
|
|
o = pa >> 25;
|
|
|
|
if(o != 0 && o != 0x7F){
|
|
|
|
/* a branch too far */
|
|
|
|
vp[3] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */
|
|
|
|
vp[4] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */
|
|
|
|
vp[5] = 0x7c0803a6; /* MOVW R0, LR */
|
|
|
|
vp[6] = 0x4e800021; /* BL (LR) */
|
|
|
|
}else
|
|
|
|
vp[3] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */
|
|
|
|
dcflush(vp, 8*sizeof(ulong));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
trapinit(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* set all exceptions to trap
|
|
|
|
*/
|
|
|
|
for(i = 0; i < 0x2000; i += 0x100)
|
|
|
|
sethvec(i, trapvec);
|
|
|
|
|
|
|
|
putmsr(getmsr() & ~MSR_IP);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
intr(Ureg *ureg)
|
|
|
|
{
|
|
|
|
int vno;
|
|
|
|
Vctl *ctl, *v;
|
|
|
|
|
|
|
|
vno = mpicintack();
|
|
|
|
if(vno == 0) { /* 8259, wired through MPIC vec 0 */
|
|
|
|
vno = i8259intack();
|
|
|
|
mpiceoi(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(vno > nelem(vctl) || (ctl = vctl[vno]) == 0) {
|
|
|
|
panic("spurious intr %d", vno);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(ctl->isr)
|
|
|
|
ctl->isr(vno);
|
|
|
|
for(v = ctl; v != nil; v = v->next){
|
|
|
|
if(v->f)
|
|
|
|
v->f(ureg, v->a);
|
|
|
|
}
|
|
|
|
if(ctl->eoi)
|
|
|
|
ctl->eoi(vno);
|
|
|
|
|
|
|
|
if(up)
|
|
|
|
preempted();
|
|
|
|
}
|
|
|
|
|
|
|
|
char*
|
|
|
|
fpexcname(Ureg *ur, ulong fpscr, char *buf)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char *s;
|
|
|
|
ulong fppc;
|
|
|
|
|
|
|
|
fppc = ur->pc;
|
|
|
|
s = 0;
|
|
|
|
fpscr >>= 3; /* trap enable bits */
|
|
|
|
fpscr &= (fpscr>>22); /* anded with exceptions */
|
|
|
|
for(i=0; i<5; i++)
|
|
|
|
if(fpscr & (1<<i))
|
|
|
|
s = fpcause[i];
|
|
|
|
if(s == 0)
|
|
|
|
return "no floating point exception";
|
|
|
|
sprint(buf, "%s fppc=0x%lux", s, fppc);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fill in enough of Ureg to get a stack trace, and call a function.
|
|
|
|
* Used by debugging interface rdb.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
|
|
|
getpcsp(ulong *pc, ulong *sp)
|
|
|
|
{
|
|
|
|
*pc = getcallerpc(&pc);
|
|
|
|
*sp = (ulong)&pc-4;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
callwithureg(void (*fn)(Ureg*))
|
|
|
|
{
|
|
|
|
Ureg ureg;
|
|
|
|
|
|
|
|
getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);
|
|
|
|
ureg.lr = getcallerpc(&fn);
|
|
|
|
fn(&ureg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_dumpstack(Ureg *ureg)
|
|
|
|
{
|
|
|
|
ulong l, sl, el, v;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
l = (ulong)&l;
|
|
|
|
if(up == 0){
|
|
|
|
el = (ulong)m+BY2PG;
|
|
|
|
sl = el-KSTACK;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
sl = (ulong)up->kstack;
|
|
|
|
el = sl + KSTACK;
|
|
|
|
}
|
|
|
|
if(l > el || l < sl){
|
|
|
|
el = (ulong)m+BY2PG;
|
|
|
|
sl = el-KSTACK;
|
|
|
|
}
|
|
|
|
if(l > el || l < sl)
|
|
|
|
return;
|
|
|
|
print("ktrace /kernel/path %.8lux %.8lux %.8lux\n", ureg->pc, ureg->sp, ureg->lr);
|
|
|
|
i = 0;
|
|
|
|
for(; l < el; l += 4){
|
|
|
|
v = *(ulong*)l;
|
|
|
|
if(KTZERO < v && v < (ulong)etext){
|
|
|
|
print("%.8lux=%.8lux ", l, v);
|
|
|
|
if(i++ == 4){
|
|
|
|
print("\n");
|
|
|
|
i = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dumpstack(void)
|
|
|
|
{
|
|
|
|
callwithureg(_dumpstack);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dumpregs(Ureg *ur)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
ulong *l;
|
|
|
|
|
|
|
|
if(up) {
|
|
|
|
print("registers for %s %ld\n", up->text, up->pid);
|
2015-06-13 18:21:26 +00:00
|
|
|
if((ur->srr1 & MSR_PR) == 0)
|
2011-03-30 12:46:40 +00:00
|
|
|
if(ur->usp < (ulong)up->kstack || ur->usp > (ulong)up->kstack+KSTACK)
|
|
|
|
print("invalid stack ptr\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
print("registers for kernel\n");
|
|
|
|
|
|
|
|
print("dsisr\t%.8lux\tdar\t%.8lux\n", getdsisr(), getdar());
|
|
|
|
l = &ur->cause;
|
|
|
|
for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2)
|
|
|
|
print("%s\t%.8lux\t%s\t%.8lux\n", regname[i], l[0], regname[i+1], l[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-12-20 21:34:41 +00:00
|
|
|
kprocchild(Proc *p, void (*entry)(void))
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2020-12-20 21:34:41 +00:00
|
|
|
p->sched.pc = (ulong)entry;
|
2011-03-30 12:46:40 +00:00
|
|
|
p->sched.sp = (ulong)p->kstack+KSTACK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* called in sysfile.c
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
evenaddr(ulong addr)
|
|
|
|
{
|
|
|
|
if(addr & 3){
|
|
|
|
postnote(up, 1, "sys: odd address", NDebug);
|
|
|
|
error(Ebadarg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
|
|
|
execregs(uintptr entry, ulong ssize, ulong nargs)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
ulong *sp;
|
|
|
|
Ureg *ureg;
|
|
|
|
|
|
|
|
sp = (ulong*)(USTKTOP - ssize);
|
|
|
|
*--sp = nargs;
|
|
|
|
|
|
|
|
ureg = up->dbgreg;
|
|
|
|
ureg->usp = (ulong)sp;
|
|
|
|
ureg->pc = entry;
|
|
|
|
ureg->srr1 &= ~MSR_FP;
|
|
|
|
return USTKTOP-sizeof(Tos); /* address of kernel/user shared data */
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
forkchild(Proc *p, Ureg *ur)
|
|
|
|
{
|
|
|
|
Ureg *cur;
|
|
|
|
|
|
|
|
p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
|
|
|
|
p->sched.pc = (ulong)forkret;
|
|
|
|
|
|
|
|
cur = (Ureg*)(p->sched.sp+2*BY2WD);
|
|
|
|
memmove(cur, ur, sizeof(Ureg));
|
|
|
|
cur->r3 = 0;
|
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
2011-03-30 12:46:40 +00:00
|
|
|
userpc(void)
|
|
|
|
{
|
|
|
|
Ureg *ureg;
|
|
|
|
|
|
|
|
ureg = (Ureg*)up->dbgreg;
|
|
|
|
return ureg->pc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* This routine must save the values of registers the user is not
|
|
|
|
* permitted to write from devproc and then restore the saved values
|
|
|
|
* before returning
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
setregisters(Ureg *xp, char *pureg, char *uva, int n)
|
|
|
|
{
|
|
|
|
ulong status;
|
|
|
|
|
|
|
|
status = xp->status;
|
|
|
|
memmove(pureg, uva, n);
|
|
|
|
xp->status = status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Give enough context in the ureg to produce a kernel stack for
|
|
|
|
* a sleeping process
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
setkernur(Ureg* ureg, Proc* p)
|
|
|
|
{
|
|
|
|
ureg->pc = p->sched.pc;
|
|
|
|
ureg->sp = p->sched.sp+4;
|
|
|
|
}
|
|
|
|
|
2014-01-19 23:47:55 +00:00
|
|
|
uintptr
|
2011-03-30 12:46:40 +00:00
|
|
|
dbgpc(Proc *p)
|
|
|
|
{
|
|
|
|
Ureg *ureg;
|
|
|
|
|
|
|
|
ureg = p->dbgreg;
|
|
|
|
if(ureg == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return ureg->pc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* system calls
|
|
|
|
*/
|
|
|
|
#include "../port/systab.h"
|
|
|
|
|
|
|
|
/* TODO: make this trap a separate asm entry point, like on other RISC architectures */
|
|
|
|
void
|
|
|
|
syscall(Ureg* ureg)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char *e;
|
|
|
|
long ret;
|
|
|
|
ulong sp, scallnr;
|
|
|
|
|
|
|
|
m->syscall++;
|
|
|
|
up->insyscall = 1;
|
|
|
|
up->pc = ureg->pc;
|
|
|
|
|
|
|
|
scallnr = ureg->r3;
|
|
|
|
up->scallnr = ureg->r3;
|
|
|
|
spllo();
|
|
|
|
|
|
|
|
sp = ureg->usp;
|
|
|
|
up->nerrlab = 0;
|
|
|
|
ret = -1;
|
|
|
|
if(!waserror()){
|
|
|
|
if(scallnr >= nsyscall || systab[scallnr] == nil){
|
|
|
|
pprint("bad sys call number %d pc %lux\n", scallnr, ureg->pc);
|
|
|
|
postnote(up, 1, "sys: bad sys call", NDebug);
|
|
|
|
error(Ebadarg);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
|
|
|
|
validaddr(sp, sizeof(Sargs)+BY2WD, 0);
|
|
|
|
|
|
|
|
up->s = *((Sargs*)(sp+BY2WD));
|
|
|
|
up->psstate = sysctab[scallnr];
|
|
|
|
|
|
|
|
ret = systab[scallnr](up->s.args);
|
|
|
|
poperror();
|
|
|
|
}else{
|
|
|
|
/* failure: save the error buffer for errstr */
|
|
|
|
e = up->syserrstr;
|
|
|
|
up->syserrstr = up->errstr;
|
|
|
|
up->errstr = e;
|
|
|
|
}
|
|
|
|
if(up->nerrlab){
|
|
|
|
print("bad errstack [%uld]: %d extra\n", scallnr, up->nerrlab);
|
|
|
|
print("scall %s lr =%lux\n", sysctab[scallnr], ureg->lr);
|
|
|
|
for(i = 0; i < NERR; i++)
|
|
|
|
print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
|
|
|
|
panic("error stack");
|
|
|
|
}
|
|
|
|
|
|
|
|
up->insyscall = 0;
|
|
|
|
up->psstate = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Put return value in frame. On the x86 the syscall is
|
|
|
|
* just another trap and the return value from syscall is
|
|
|
|
* ignored. On other machines the return value is put into
|
|
|
|
* the results register by caller of syscall.
|
|
|
|
*/
|
|
|
|
ureg->r3 = ret;
|
|
|
|
|
|
|
|
if(scallnr == NOTED)
|
|
|
|
noted(ureg, *(ulong*)(sp+BY2WD));
|
|
|
|
|
|
|
|
/* restoreureg must execute at high IPL */
|
|
|
|
splhi();
|
|
|
|
if(scallnr!=RFORK)
|
|
|
|
notify(ureg);
|
|
|
|
if(up->fpstate == FPinactive)
|
|
|
|
ureg->srr1 &= ~MSR_FP;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Call user, if necessary, with note.
|
|
|
|
* Pass user the Ureg struct and the note on his stack.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
notify(Ureg* ur)
|
|
|
|
{
|
|
|
|
int l;
|
|
|
|
ulong s, sp;
|
|
|
|
Note *n;
|
|
|
|
|
|
|
|
if(up->procctl)
|
2014-11-09 07:19:28 +00:00
|
|
|
procctl();
|
2011-03-30 12:46:40 +00:00
|
|
|
if(up->nnote == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
s = spllo();
|
|
|
|
qlock(&up->debug);
|
|
|
|
up->notepending = 0;
|
|
|
|
n = &up->note[0];
|
|
|
|
if(strncmp(n->msg, "sys:", 4) == 0){
|
|
|
|
l = strlen(n->msg);
|
|
|
|
if(l > ERRMAX-15) /* " pc=0x12345678\0" */
|
|
|
|
l = ERRMAX-15;
|
|
|
|
sprint(n->msg+l, " pc=0x%.8lux", ur->pc);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(n->flag!=NUser && (up->notified || up->notify==0)){
|
2013-12-29 06:48:19 +00:00
|
|
|
qunlock(&up->debug);
|
2011-03-30 12:46:40 +00:00
|
|
|
if(n->flag == NDebug)
|
|
|
|
pprint("suicide: %s\n", n->msg);
|
|
|
|
pexit(n->msg, n->flag!=NDebug);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(up->notified) {
|
|
|
|
qunlock(&up->debug);
|
|
|
|
splhi();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!up->notify) {
|
|
|
|
qunlock(&up->debug);
|
|
|
|
pexit(n->msg, n->flag!=NDebug);
|
|
|
|
}
|
|
|
|
sp = ur->usp & ~(BY2V-1);
|
|
|
|
sp -= sizeof(Ureg);
|
|
|
|
|
2014-01-20 01:16:42 +00:00
|
|
|
if(!okaddr((uintptr)up->notify, BY2WD, 0) ||
|
2011-03-30 12:46:40 +00:00
|
|
|
!okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
|
|
|
|
qunlock(&up->debug);
|
2013-12-29 06:48:19 +00:00
|
|
|
pprint("suicide: bad address or sp in notify\n");
|
2011-03-30 12:46:40 +00:00
|
|
|
pexit("Suicide", 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
memmove((Ureg*)sp, ur, sizeof(Ureg));
|
|
|
|
*(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
|
|
|
|
up->ureg = (void*)sp;
|
|
|
|
sp -= BY2WD+ERRMAX;
|
|
|
|
memmove((char*)sp, up->note[0].msg, ERRMAX);
|
|
|
|
sp -= 3*BY2WD;
|
|
|
|
*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */
|
|
|
|
ur->r1 = (long)up->ureg; /* arg 1 is ureg* */
|
|
|
|
((ulong*)sp)[1] = (ulong)up->ureg; /* arg 1 0(FP) is ureg* */
|
|
|
|
((ulong*)sp)[0] = 0; /* arg 0 is pc */
|
|
|
|
ur->usp = sp;
|
|
|
|
ur->pc = (ulong)up->notify;
|
|
|
|
up->notified = 1;
|
|
|
|
up->nnote--;
|
|
|
|
memmove(&up->lastnote, &up->note[0], sizeof(Note));
|
|
|
|
memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
|
|
|
|
|
|
|
|
qunlock(&up->debug);
|
|
|
|
splx(s);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return user to state before notify()
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
noted(Ureg* ureg, ulong arg0)
|
|
|
|
{
|
|
|
|
Ureg *nureg;
|
|
|
|
ulong oureg, sp;
|
|
|
|
|
|
|
|
qlock(&up->debug);
|
|
|
|
if(arg0!=NRSTR && !up->notified) {
|
|
|
|
qunlock(&up->debug);
|
|
|
|
pprint("call to noted() when not notified\n");
|
|
|
|
pexit("Suicide", 0);
|
|
|
|
}
|
|
|
|
up->notified = 0;
|
|
|
|
|
|
|
|
nureg = up->ureg; /* pointer to user returned Ureg struct */
|
|
|
|
|
|
|
|
/* sanity clause */
|
|
|
|
oureg = (ulong)nureg;
|
2014-01-20 01:16:42 +00:00
|
|
|
if(!okaddr(oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
|
2011-03-30 12:46:40 +00:00
|
|
|
qunlock(&up->debug);
|
2013-12-29 06:48:19 +00:00
|
|
|
pprint("bad ureg in noted or call to noted when not notified\n");
|
2011-03-30 12:46:40 +00:00
|
|
|
pexit("Suicide", 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
memmove(ureg, nureg, sizeof(Ureg));
|
|
|
|
|
|
|
|
switch(arg0){
|
|
|
|
case NCONT:
|
|
|
|
case NRSTR:
|
|
|
|
if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
|
|
|
|
qunlock(&up->debug);
|
2013-12-29 06:48:19 +00:00
|
|
|
pprint("suicide: trap in noted\n");
|
2011-03-30 12:46:40 +00:00
|
|
|
pexit("Suicide", 0);
|
|
|
|
}
|
|
|
|
up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
|
|
|
|
qunlock(&up->debug);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NSAVE:
|
|
|
|
if(!okaddr(nureg->pc, BY2WD, 0)
|
|
|
|
|| !okaddr(nureg->usp, BY2WD, 0)){
|
|
|
|
qunlock(&up->debug);
|
2013-12-29 06:48:19 +00:00
|
|
|
pprint("suicide: trap in noted\n");
|
2011-03-30 12:46:40 +00:00
|
|
|
pexit("Suicide", 0);
|
|
|
|
}
|
|
|
|
qunlock(&up->debug);
|
|
|
|
sp = oureg-4*BY2WD-ERRMAX;
|
|
|
|
splhi();
|
|
|
|
ureg->sp = sp;
|
|
|
|
((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */
|
|
|
|
((ulong*)sp)[0] = 0; /* arg 0 is pc */
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
up->lastnote.flag = NDebug;
|
|
|
|
/* fall through */
|
|
|
|
|
|
|
|
case NDFLT:
|
2013-12-29 06:48:19 +00:00
|
|
|
qunlock(&up->debug);
|
2011-03-30 12:46:40 +00:00
|
|
|
if(up->lastnote.flag == NDebug)
|
|
|
|
pprint("suicide: %s\n", up->lastnote.msg);
|
|
|
|
pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
|
|
|
|
}
|
|
|
|
}
|