shithub: powernv

ref: a691c9111a69257e206ce895d35396d0f6225929
dir: /trap.c/

View raw version
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
#include "../port/systab.h"

#include <tos.h>
#include "ureg.h"

int	(*buserror)(Ureg*);

/* SPSR bits user can modify */
#define USPSRMASK	(0xFULL<<28)

void
trapinit(void)
{
}

static char *traps[64] = {
	[0x00]	"sys: trap: unknown",
	[0x01]	"sys: trap: WFI or WFE instruction execution",
	[0x0E]	"sys: trap: illegal execution state",
	[0x18]	"sys: trap: illegal MSR/MRS access",
	[0x22]	"sys: trap: misaligned pc",
	[0x26]	"sys: trap: stack pointer misaligned",
	[0x30]	"sys: breakpoint",
	[0x32]	"sys: software step",
	[0x34]	"sys: watchpoint",
	[0x3C]	"sys: breakpoint",
};

void
trap(Ureg *ureg)
{
}

void
syscall(Ureg *ureg)
{
	vlong startns, stopns;
	uintptr sp, ret;
	ulong scallnr;
	int i, s;
	char *e;

	if(!kenter(ureg))
		panic("syscall from  kernel");
	fpukenter(ureg);
	
	m->syscall++;
	up->insyscall = 1;
	up->pc = ureg->pc;
	
	sp = ureg->sp;
	up->scallnr = scallnr = ureg->r0;
	spllo();
	
	up->nerrlab = 0;
	startns = 0;
	ret = -1;
	if(!waserror()){
		if(sp < USTKTOP - BY2PG || sp > USTKTOP - sizeof(Sargs) - BY2WD){
			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
			evenaddr(sp);
		}
		up->s = *((Sargs*) (sp + BY2WD));

		if(up->procctl == Proc_tracesyscall){
			syscallfmt(scallnr, ureg->pc, (va_list) up->s.args);
			s = splhi();
			up->procctl = Proc_stopme;
			procctl();
			splx(s);
			startns = todget(nil);
		}
		
		if(scallnr >= nsyscall || systab[scallnr] == nil){
			postnote(up, 1, "sys: bad sys call", NDebug);
			error(Ebadarg);
		}
		up->psstate = sysctab[scallnr];
		ret = systab[scallnr]((va_list)up->s.args);
		poperror();
	}else{
		e = up->syserrstr;
		up->syserrstr = up->errstr;
		up->errstr = e;
	}
	if(up->nerrlab){
		print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
		for(i = 0; i < NERR; i++)
			print("sp=%#p pc=%#p\n", up->errlab[i].sp, up->errlab[i].pc);
		panic("error stack");
	}
	ureg->r0 = ret;
	if(up->procctl == Proc_tracesyscall){
		stopns = todget(nil);
		sysretfmt(scallnr, (va_list) up->s.args, ret, startns, stopns);
		s = splhi();
		up->procctl = Proc_stopme;
		procctl();
		splx(s);
	}
	up->insyscall = 0;
	up->psstate = 0;

	if(scallnr == NOTED){
		noted(ureg, *((ulong*) up->s.args));
		/*
		 * normally, syscall() returns to forkret()
		 * not restoring general registers when going
		 * to userspace. to completely restore the
		 * interrupted context, we have to return thru
		 * noteret(). we override return pc to jump to
		 * to it when returning form syscall()
		 */
		returnto(noteret);

		splhi();
		up->fpstate &= ~FPillegal;
	}
	else
		splhi();

	if(scallnr != RFORK && (up->procctl || up->nnote))
		notify(ureg);

	if(up->delaysched){
		sched();
		splhi();
	}

	kexit(ureg);
	fpukexit(ureg, nil);
}

int
notify(Ureg *ureg)
{
	uintptr sp;
	char *msg;

	if(up->procctl)
		procctl();
	if(up->nnote == 0)
		return 0;

	spllo();
	qlock(&up->debug);
	msg = popnote(ureg);
	if(msg == nil){
		qunlock(&up->debug);
		splhi();
		return 0;
	}

	sp = ureg->sp;
	sp -= 256;	/* debugging: preserve context causing problem */
	sp -= sizeof(Ureg);
	sp = STACKALIGN(sp);

	if(!okaddr((uintptr)up->notify, 1, 0)
	|| !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)
	|| ((uintptr) up->notify & 3) != 0
	|| (sp & 7) != 0){
		qunlock(&up->debug);
		pprint("suicide: bad address in notify: handler=%#p sp=%#p\n",
			up->notify, sp);
		pexit("Suicide", 0);
	}

	memmove((Ureg*)sp, ureg, sizeof(Ureg));
	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
	up->ureg = (void*)sp;
	sp -= BY2WD+ERRMAX;
	memmove((char*)sp, msg, ERRMAX);
	sp -= 3*BY2WD;
	*(uintptr*)(sp+2*BY2WD) = sp+3*BY2WD;
	*(uintptr*)(sp+1*BY2WD) = (uintptr)up->ureg;
	ureg->r0 = (uintptr) up->ureg;
	ureg->sp = sp;
	ureg->pc = (uintptr) up->notify;
	ureg->cause = 0;
	qunlock(&up->debug);

	splhi();
	fpuprocsave(up);
	up->fpstate |= FPillegal;
	return 1;
}

void
noted(Ureg *ureg, ulong arg0)
{
}

static void
faultnote(Ureg *ureg, char *access, uintptr addr)
{
}

int
userureg(Ureg* ureg)
{
	return 0;
}

uintptr
userpc(void)
{
	Ureg *ur = up->dbgreg;
	return ur->pc;
}

uintptr
dbgpc(Proc *)
{
	Ureg *ur = up->dbgreg;
	if(ur == nil)
		return 0;
	return ur->pc;
}

void
procfork(Proc *p)
{
	fpuprocfork(p);
	p->tpidr = up->tpidr;
}

void
procsetup(Proc *p)
{
}

void
procsave(Proc *p)
{
}

void
procrestore(Proc *p)
{
}

void
kprocchild(Proc *p, void (*entry)(void))
{
}

void
forkchild(Proc *p, Ureg *ureg)
{
}

uintptr
execregs(uintptr entry, ulong ssize, ulong nargs)
{
	return 0;
}

void
evenaddr(uintptr addr)
{
}

void
callwithureg(void (*f) (Ureg *))
{
}

void
setkernur(Ureg *ureg, Proc *p)
{
}

void
setupwatchpts(Proc*, Watchpt*, int)
{
}

void
setregisters(Ureg* ureg, char* pureg, char* uva, int n)
{
}

static void
dumpstackwithureg(Ureg *ureg)
{
}

void
dumpstack(void)
{
	callwithureg(dumpstackwithureg);
}

void
dumpregs(Ureg *ureg)
{
}