2016-11-25 17:18:40 +01:00
|
|
|
/*
|
|
|
|
* This file is part of Jehanne.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2015-2016 Giacomo Tesio <giacomo@tesio.it>
|
|
|
|
*
|
|
|
|
* Jehanne is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, version 2 of the License.
|
|
|
|
*
|
|
|
|
* Jehanne is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
#include "u.h"
|
|
|
|
#include "../port/lib.h"
|
|
|
|
#include "mem.h"
|
|
|
|
#include "dat.h"
|
|
|
|
#include "fns.h"
|
|
|
|
|
|
|
|
#include "../port/error.h"
|
|
|
|
|
|
|
|
#include <ptrace.h>
|
|
|
|
|
|
|
|
#include "amd64.h"
|
|
|
|
#include "ureg.h"
|
|
|
|
|
|
|
|
extern int printallsyscalls;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
uintptr_t ip;
|
|
|
|
Ureg* arg0;
|
|
|
|
char* arg1;
|
|
|
|
char msg[ERRMAX];
|
|
|
|
Ureg* old;
|
|
|
|
Ureg ureg;
|
|
|
|
} NFrame;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return user to state before notify()
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
noted(Ureg* cur, uintptr_t arg0)
|
|
|
|
{
|
|
|
|
NFrame *nf;
|
|
|
|
Note note;
|
|
|
|
Ureg *nur;
|
|
|
|
|
|
|
|
qlock(&up->debug);
|
|
|
|
if(arg0 != NRSTR && !up->notified){
|
|
|
|
qunlock(&up->debug);
|
|
|
|
pprint("suicide: call to noted when not notified\n");
|
|
|
|
pexit("Suicide", 0);
|
|
|
|
}
|
|
|
|
up->notified = 0;
|
|
|
|
fpunoted();
|
|
|
|
|
|
|
|
nf = up->ureg;
|
|
|
|
|
|
|
|
/* sanity clause */
|
|
|
|
if(!okaddr(PTR2UINT(nf), sizeof(NFrame), 0)){
|
|
|
|
qunlock(&up->debug);
|
|
|
|
pprint("suicide: bad ureg %#p in noted\n", nf);
|
|
|
|
pexit("Suicide", 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check the segment selectors are all valid.
|
|
|
|
*/
|
|
|
|
nur = &nf->ureg;
|
|
|
|
if(nur->cs != SSEL(SiUCS, SsRPL3) || nur->ss != SSEL(SiUDS, SsRPL3)
|
|
|
|
// || nur->ds != SSEL(SiUDS, SsRPL3) || nur->es != SSEL(SiUDS, SsRPL3)
|
|
|
|
// || nur->fs != SSEL(SiUDS, SsRPL3) || nur->gs != SSEL(SiUDS, SsRPL3)
|
|
|
|
){
|
|
|
|
qunlock(&up->debug);
|
|
|
|
pprint("suicide: bad segment selector in noted\n");
|
|
|
|
pexit("Suicide", 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* don't let user change system flags */
|
|
|
|
nur->flags &= (Of|Df|Sf|Zf|Af|Pf|Cf);
|
|
|
|
nur->flags |= cur->flags & ~(Of|Df|Sf|Zf|Af|Pf|Cf);
|
|
|
|
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(cur, nur, sizeof(Ureg));
|
2016-11-25 17:18:40 +01:00
|
|
|
|
|
|
|
switch((int)arg0){
|
|
|
|
case NCONT:
|
|
|
|
case NRSTR:
|
|
|
|
if(!okaddr(nur->ip, BY2SE, 0) || !okaddr(nur->sp, BY2SE, 0)){
|
|
|
|
qunlock(&up->debug);
|
|
|
|
pprint("suicide: trap in noted pc=%#p sp=%#p\n",
|
|
|
|
nur->ip, nur->sp);
|
|
|
|
pexit("Suicide", 0);
|
|
|
|
}
|
|
|
|
up->ureg = nf->old;
|
|
|
|
qunlock(&up->debug);
|
|
|
|
break;
|
|
|
|
case NSAVE:
|
|
|
|
if(!okaddr(nur->ip, BY2SE, 0) || !okaddr(nur->sp, BY2SE, 0)){
|
|
|
|
qunlock(&up->debug);
|
|
|
|
pprint("suicide: trap in noted pc=%#p sp=%#p\n",
|
|
|
|
nur->ip, nur->sp);
|
|
|
|
pexit("Suicide", 0);
|
|
|
|
}
|
|
|
|
qunlock(&up->debug);
|
|
|
|
|
|
|
|
splhi();
|
|
|
|
nf->arg1 = nf->msg;
|
|
|
|
nf->arg0 = &nf->ureg;
|
|
|
|
cur->bp = PTR2UINT(nf->arg0);
|
|
|
|
nf->ip = 0;
|
|
|
|
cur->sp = PTR2UINT(nf);
|
|
|
|
break;
|
|
|
|
default:
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(¬e, &up->lastnote, sizeof(Note));
|
2016-11-25 17:18:40 +01:00
|
|
|
qunlock(&up->debug);
|
|
|
|
pprint("suicide: bad arg %#p in noted: %s\n", arg0, note.msg);
|
|
|
|
pexit(note.msg, 0);
|
|
|
|
break;
|
|
|
|
case NDFLT:
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(¬e, &up->lastnote, sizeof(Note));
|
2016-11-25 17:18:40 +01:00
|
|
|
qunlock(&up->debug);
|
|
|
|
if(note.flag == NDebug)
|
|
|
|
pprint("suicide: %s\n", note.msg);
|
|
|
|
pexit(note.msg, note.flag != NDebug);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Call user, if necessary, with note.
|
|
|
|
* Pass user the Ureg struct and the note on his stack.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
notify(Ureg* ureg)
|
|
|
|
{
|
|
|
|
int l;
|
|
|
|
Mreg s;
|
|
|
|
Note note;
|
|
|
|
uintptr_t sp;
|
|
|
|
NFrame *nf;
|
|
|
|
|
|
|
|
if(up->procctl)
|
|
|
|
procctl(up);
|
|
|
|
if(up->nnote == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
fpunotify(ureg);
|
|
|
|
|
|
|
|
s = spllo();
|
|
|
|
qlock(&up->debug);
|
|
|
|
|
|
|
|
up->notepending = 0;
|
|
|
|
up->notedeferred = 0;
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(¬e, &up->note[0], sizeof(Note));
|
|
|
|
if(jehanne_strncmp(note.msg, "sys:", 4) == 0){
|
|
|
|
l = jehanne_strlen(note.msg);
|
2016-11-25 17:18:40 +01:00
|
|
|
if(l > ERRMAX-sizeof(" pc=0x0123456789abcdef"))
|
|
|
|
l = ERRMAX-sizeof(" pc=0x0123456789abcdef");
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_sprint(note.msg+l, " pc=%#p", ureg->ip);
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if(note.flag != NUser && (up->notified || up->notify == nil)){
|
|
|
|
qunlock(&up->debug);
|
|
|
|
if(note.flag == NDebug)
|
|
|
|
pprint("suicide: %s\n", note.msg);
|
|
|
|
pexit(note.msg, note.flag != NDebug);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(up->notified){
|
|
|
|
qunlock(&up->debug);
|
|
|
|
splhi();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(up->notify == nil){
|
|
|
|
qunlock(&up->debug);
|
|
|
|
pexit(note.msg, note.flag != NDebug);
|
|
|
|
}
|
|
|
|
if(!okaddr(PTR2UINT(up->notify), sizeof(ureg->ip), 0)){
|
|
|
|
qunlock(&up->debug);
|
|
|
|
pprint("suicide: bad function address %#p in notify\n",
|
|
|
|
up->notify);
|
|
|
|
pexit("Suicide", 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
sp = ureg->sp - sizeof(NFrame);
|
|
|
|
if(!okaddr(sp, sizeof(NFrame), 1)){
|
|
|
|
qunlock(&up->debug);
|
|
|
|
pprint("suicide: bad stack address %#p in notify\n", sp);
|
|
|
|
pexit("Suicide", 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
nf = UINT2PTR(sp);
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(&nf->ureg, ureg, sizeof(Ureg));
|
2016-11-25 17:18:40 +01:00
|
|
|
nf->old = up->ureg;
|
|
|
|
up->ureg = nf;
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(nf->msg, note.msg, ERRMAX);
|
2016-11-25 17:18:40 +01:00
|
|
|
nf->arg1 = nf->msg;
|
|
|
|
nf->arg0 = &nf->ureg;
|
|
|
|
ureg->di = (uintptr_t)nf->arg0;
|
|
|
|
ureg->si = (uintptr_t)nf->arg1;
|
|
|
|
ureg->bp = PTR2UINT(nf->arg0);
|
|
|
|
nf->ip = 0;
|
|
|
|
|
|
|
|
ureg->sp = sp;
|
|
|
|
ureg->ip = PTR2UINT(up->notify);
|
|
|
|
up->notified = 1;
|
|
|
|
up->nnote--;
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(&up->lastnote, ¬e, sizeof(Note));
|
|
|
|
jehanne_memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
|
2016-11-25 17:18:40 +01:00
|
|
|
|
|
|
|
qunlock(&up->debug);
|
|
|
|
splx(s);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
syscall(Syscalls scallnr, Ureg* ureg)
|
|
|
|
{
|
|
|
|
char *tmp;
|
|
|
|
uintptr_t sp;
|
|
|
|
int i, s;
|
|
|
|
char *str;
|
|
|
|
int64_t startns, stopns;
|
|
|
|
ScRet retv;
|
|
|
|
void (*pt)(Proc*, int, int64_t, int64_t);
|
|
|
|
|
|
|
|
if(!userureg(ureg))
|
|
|
|
panic("syscall: cs %#llux\n", ureg->cs);
|
|
|
|
|
|
|
|
cycles(&up->kentry);
|
|
|
|
|
|
|
|
m->syscall++;
|
2017-05-17 01:16:49 +02:00
|
|
|
up->inkernel = 1;
|
2017-05-15 00:05:59 +02:00
|
|
|
up->cursyscall = (Syscalls)scallnr;
|
2017-05-17 02:04:08 +02:00
|
|
|
up->blockingsc = 0;
|
2016-11-25 17:18:40 +01:00
|
|
|
up->pc = ureg->ip;
|
|
|
|
up->dbgreg = ureg;
|
|
|
|
if(up->trace && (pt = proctrace) != nil)
|
|
|
|
pt(up, STrap, todget(nil), STrapSC|scallnr);
|
|
|
|
|
|
|
|
if(up->procctl == Proc_tracesyscall){
|
|
|
|
up->procctl = Proc_stopme;
|
|
|
|
procctl(up);
|
|
|
|
}
|
|
|
|
|
|
|
|
up->scallnr = scallnr;
|
|
|
|
if(scallnr == SysRfork)
|
|
|
|
fpusysrfork(ureg);
|
|
|
|
spllo();
|
|
|
|
|
|
|
|
startns = 0;
|
|
|
|
sp = ureg->sp;
|
|
|
|
up->nerrlab = 0;
|
|
|
|
retv = default_syscall_ret(scallnr);
|
|
|
|
if(!waserror()){
|
|
|
|
tmp = syscall_name(scallnr);
|
|
|
|
if(tmp == nil){
|
|
|
|
pprint("bad sys call number %d pc %#llux\n", scallnr, ureg->ip);
|
|
|
|
postnote(up, 1, "sys: bad sys call", NDebug);
|
|
|
|
error(Ebadarg);
|
|
|
|
}
|
|
|
|
if(sp < (USTKTOP-PGSZ) || sp > (USTKTOP-sizeof(up->arg)-BY2SE))
|
|
|
|
validaddr(UINT2PTR(sp), sizeof(up->arg)+BY2SE, 0);
|
|
|
|
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(up->arg, UINT2PTR(sp+BY2SE), sizeof(up->arg));
|
2016-11-25 17:18:40 +01:00
|
|
|
up->psstate = tmp;
|
|
|
|
|
|
|
|
if(printallsyscalls || up->syscallq != nil){
|
|
|
|
str = syscallfmt(scallnr, ureg);
|
|
|
|
if(printallsyscalls){
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_print("%s\n", str);
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
if(up->syscallq != nil){
|
|
|
|
qlock(&up->debug);
|
|
|
|
if(up->syscallq != nil){
|
|
|
|
notedefer();
|
|
|
|
if(!waserror()){
|
2017-04-19 23:33:14 +02:00
|
|
|
qwrite(up->syscallq, str, jehanne_strlen(str));
|
2016-11-25 17:18:40 +01:00
|
|
|
poperror();
|
|
|
|
}
|
|
|
|
noteallow();
|
|
|
|
}
|
|
|
|
qunlock(&up->debug);
|
|
|
|
}
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_free(str);
|
2016-11-25 17:18:40 +01:00
|
|
|
startns = todget(nil);
|
|
|
|
}
|
|
|
|
dispatch_syscall(scallnr, ureg, &retv);
|
|
|
|
poperror();
|
|
|
|
} else {
|
|
|
|
/* failure: save the error buffer for errstr */
|
2016-11-30 01:07:45 +01:00
|
|
|
retv.l = up->syscallerr;
|
2016-11-25 17:18:40 +01:00
|
|
|
tmp = up->syserrstr;
|
|
|
|
up->syserrstr = up->errstr;
|
|
|
|
up->errstr = tmp;
|
|
|
|
if(DBGFLG && up->pid == 1)
|
|
|
|
iprint("%s: syscall %s error %s\n",
|
|
|
|
up->text, syscall_name(scallnr), up->syserrstr);
|
|
|
|
}
|
|
|
|
if(up->nerrlab){
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab);
|
2016-11-25 17:18:40 +01:00
|
|
|
for(i = 0; i < NERR; i++)
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_print("sp=%#p pc=%#p\n",
|
2016-11-25 17:18:40 +01:00
|
|
|
up->errlab[i].sp, up->errlab[i].pc);
|
|
|
|
panic("error stack");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Put return value in frame.
|
|
|
|
* Which element of ScRet to use is based on specific
|
|
|
|
* knowledge of the architecture.
|
|
|
|
*/
|
|
|
|
ureg->ax = retv.p;
|
|
|
|
if(printallsyscalls || up->syscallq != nil){
|
|
|
|
stopns = todget(nil);
|
|
|
|
str = sysretfmt(scallnr, ureg, &retv, startns, stopns);
|
|
|
|
if(printallsyscalls){
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_print("%s\n", str);
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
if(up->syscallq != nil){
|
|
|
|
qlock(&up->debug);
|
|
|
|
if(up->syscallq != nil){
|
|
|
|
notedefer();
|
|
|
|
if(!waserror()){
|
2017-04-19 23:33:14 +02:00
|
|
|
qwrite(up->syscallq, str, jehanne_strlen(str));
|
2016-11-25 17:18:40 +01:00
|
|
|
poperror();
|
|
|
|
}
|
|
|
|
noteallow();
|
|
|
|
}
|
|
|
|
qunlock(&up->debug);
|
|
|
|
}
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_free(str);
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if(up->procctl == Proc_tracesyscall){
|
|
|
|
up->procctl = Proc_stopme;
|
|
|
|
s = splhi();
|
|
|
|
procctl(up);
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
2017-05-17 01:16:49 +02:00
|
|
|
up->inkernel = 0;
|
2016-11-25 17:18:40 +01:00
|
|
|
up->psstate = 0;
|
2017-05-15 00:05:59 +02:00
|
|
|
up->cursyscall = 0;
|
2016-11-25 17:18:40 +01:00
|
|
|
|
|
|
|
if(scallnr == SysNoted)
|
|
|
|
noted(ureg, ureg->di);
|
|
|
|
|
|
|
|
splhi();
|
2017-01-06 01:40:04 +01:00
|
|
|
if(scallnr != SysRfork && (up->procctl || up->nnote))
|
2016-11-25 17:18:40 +01:00
|
|
|
notify(ureg);
|
2017-05-17 02:04:08 +02:00
|
|
|
else if(up->blockingsc){
|
|
|
|
if(up->blockingsc != scallnr)
|
|
|
|
panic("syscall: up->blockingsc dirty");
|
|
|
|
if(canwakeup(scallnr))
|
|
|
|
awokeproc(up);
|
|
|
|
up->blockingsc = 0;
|
|
|
|
}
|
2016-11-25 17:18:40 +01:00
|
|
|
|
|
|
|
/* if we delayed sched because we held a lock, sched now */
|
|
|
|
if(up->delaysched){
|
|
|
|
sched();
|
|
|
|
splhi();
|
|
|
|
}
|
|
|
|
kexit(ureg);
|
|
|
|
}
|
|
|
|
|
|
|
|
uintptr_t
|
|
|
|
sysexecstack(uintptr_t stack, int argc)
|
|
|
|
{
|
|
|
|
uintptr_t sp;
|
|
|
|
/*
|
|
|
|
* Given a current bottom-of-stack that have spaces for a count
|
|
|
|
* of pointer arguments that will be written it and for
|
|
|
|
* an integer argument count, return a suitably
|
|
|
|
* aligned new bottom-of-stack which will satisfy any
|
|
|
|
* hardware stack-alignment contraints.
|
|
|
|
* Rounding the stack down to be aligned with the
|
|
|
|
* natural size of a pointer variable usually suffices,
|
|
|
|
* but some architectures impose further restrictions,
|
|
|
|
* e.g. 32-bit SPARC, where the stack must be 8-byte
|
|
|
|
* aligned although pointers and integers are 32-bits.
|
|
|
|
*/
|
|
|
|
|
|
|
|
sp = STACKALIGN(stack);
|
|
|
|
/* but we need to align the stack to 16 bytes, not 8
|
|
|
|
*/
|
|
|
|
sp -= sp & 8 ? 8 : 0;
|
2017-04-19 23:33:14 +02:00
|
|
|
//jehanne_print("For %d args, sp is now %p\n", argc, sp);
|
2016-11-25 17:18:40 +01:00
|
|
|
return sp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void*
|
|
|
|
sysexecregs(uintptr_t entry, uint32_t ssize)
|
|
|
|
{
|
|
|
|
uintptr_t *sp;
|
|
|
|
Ureg *ureg;
|
|
|
|
|
|
|
|
// We made sure it was correctly aligned in sysexecstack, above.
|
|
|
|
if (ssize & 0xf) {
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_print("your stack is wrong: stacksize is not 16-byte aligned: %d\n", ssize);
|
2016-11-25 17:18:40 +01:00
|
|
|
panic("misaligned stack in sysexecregs");
|
|
|
|
}
|
|
|
|
sp = (uintptr_t*)(USTKTOP - ssize);
|
|
|
|
|
|
|
|
ureg = up->dbgreg;
|
|
|
|
ureg->sp = PTR2UINT(sp);
|
|
|
|
ureg->ip = entry;
|
|
|
|
ureg->type = 64; /* fiction for acid */
|
|
|
|
ureg->r12 = up->pid;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* return the address of kernel/user shared data
|
|
|
|
* (e.g. clock stuff)
|
|
|
|
*/
|
|
|
|
return UINT2PTR(USTKTOP);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sysprocsetup(Proc* p)
|
|
|
|
{
|
|
|
|
fpusysprocsetup(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sysrforkchild(Proc* child, Proc* parent)
|
|
|
|
{
|
|
|
|
Ureg *cureg;
|
|
|
|
|
|
|
|
// In Forsyth's 9k kernel STACKPAD was 3.
|
|
|
|
// We use 1 to match the l64vsyscall.S we imported from Harvey.
|
|
|
|
#define STACKPAD 1 /* for return PC? */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add STACKPAD*BY2SE to the stack to account for
|
|
|
|
* - the return PC
|
|
|
|
* (NOT NOW) - trap's arguments (syscallnr, ureg)
|
|
|
|
*/
|
|
|
|
child->sched.sp = PTR2UINT(child->kstack+KSTACK-((sizeof(Ureg)+STACKPAD*BY2SE)));
|
|
|
|
child->sched.pc = PTR2UINT(sysrforkret);
|
|
|
|
|
|
|
|
cureg = (Ureg*)(child->sched.sp+STACKPAD*BY2SE);
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(cureg, parent->dbgreg, sizeof(Ureg));
|
2016-11-25 17:18:40 +01:00
|
|
|
|
|
|
|
/* Things from bottom of syscall which were never executed */
|
|
|
|
child->psstate = 0;
|
2017-05-17 01:16:49 +02:00
|
|
|
child->inkernel = 0;
|
2016-11-25 17:18:40 +01:00
|
|
|
|
|
|
|
fpusysrforkchild(child, parent);
|
|
|
|
}
|