1 /* we use l1 and l2 cache ops to help stability. */
4 #include "../port/lib.h"
8 #include "../port/error.h"
9 #include "../port/systab.h"
17 Psrsysbits = PsrMask | PsrDfiq | PsrDirq | PsrDasabt | PsrMbz,
30 * Return user to state before notify()
33 noted(Ureg* cur, uintptr arg0)
39 if(arg0 != NRSTR && !up->notified){
41 pprint("call to noted() when not notified\n");
50 if(!okaddr((uintptr)nf, sizeof(NFrame), 0)){
52 pprint("bad ureg in noted %#p\n", nf);
56 /* don't let user change system flags */
58 nur->psr &= Psrsysbits;
59 nur->psr |= cur->psr & ~Psrsysbits;
61 memmove(cur, nur, sizeof(Ureg));
66 if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->sp, BY2WD, 0)){
68 pprint("suicide: trap in noted\n");
75 if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->sp, BY2WD, 0)){
77 pprint("suicide: trap in noted\n");
86 cur->sp = (uintptr)nf;
87 cur->r0 = (uintptr)nf->arg0;
90 up->lastnote.flag = NDebug;
94 if(up->lastnote.flag == NDebug)
95 pprint("suicide: %s\n", up->lastnote.msg);
96 pexit(up->lastnote.msg, up->lastnote.flag != NDebug);
101 * Call user, if necessary, with note.
102 * Pass user the Ureg struct and the note on his stack.
125 if(strncmp(n->msg, "sys:", 4) == 0){
127 if(l > ERRMAX-23) /* " pc=0x0123456789abcdef\0" */
129 snprint(n->msg + l, sizeof n->msg - l, " pc=%#lux", ureg->pc);
132 if(n->flag != NUser && (up->notified || up->notify == 0)){
134 if(n->flag == NDebug)
135 pprint("suicide: %s\n", n->msg);
136 pexit(n->msg, n->flag != NDebug);
145 if(up->notify == nil){
147 pexit(n->msg, n->flag != NDebug);
149 if(!okaddr((uintptr)up->notify, 1, 0)){
151 pprint("suicide: notify function address %#p\n", up->notify);
155 sp = ureg->sp - sizeof(NFrame);
156 if(!okaddr(sp, sizeof(NFrame), 1)){
158 pprint("suicide: notify stack address %#p\n", sp);
163 memmove(&nf->ureg, ureg, sizeof(Ureg));
166 memmove(nf->msg, up->note[0].msg, ERRMAX);
168 nf->arg0 = &nf->ureg;
172 ureg->pc = (uintptr)up->notify;
173 ureg->r0 = (uintptr)nf->arg0;
177 memmove(&up->lastnote, &up->note[0], sizeof(Note));
178 memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
183 l1cache->wb(); /* is this needed? */
195 vlong startns, stopns;
198 panic("syscall: from kernel: pc %#lux r14 %#lux psr %#lux",
199 ureg->pc, ureg->r14, ureg->psr);
209 up->scallnr = scallnr;
213 if(up->procctl == Proc_tracesyscall){
215 * Redundant validaddr. Do we care?
216 * Tracing syscalls is not exactly a fast path...
217 * Beware, validaddr currently does a pexit rather
218 * than an error if there's a problem; that might
219 * change in the future.
221 if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
222 validaddr(sp, sizeof(Sargs)+BY2WD, 0);
224 syscallfmt(scallnr, ureg->pc, (va_list)(sp+BY2WD));
225 up->procctl = Proc_stopme;
227 if (up->syscalltrace)
228 free(up->syscalltrace);
229 up->syscalltrace = nil;
234 startns = todget(nil);
236 l1cache->wb(); /* system is more stable with this */
238 if(scallnr >= nsyscall){
239 pprint("bad sys call number %d pc %#lux\n",
241 postnote(up, 1, "sys: bad sys call", NDebug);
245 if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
246 validaddr(sp, sizeof(Sargs)+BY2WD, 0);
248 up->s = *((Sargs*)(sp+BY2WD));
249 up->psstate = sysctab[scallnr];
251 /* iprint("%s: syscall %s\n", up->text, sysctab[scallnr]?sysctab[scallnr]:"huh?"); */
253 ret = systab[scallnr]((va_list)up->s.args);
256 /* failure: save the error buffer for errstr */
258 up->syserrstr = up->errstr;
262 print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab);
263 for(i = 0; i < NERR; i++)
264 print("sp=%#p pc=%#p\n",
265 up->errlab[i].sp, up->errlab[i].pc);
266 panic("error stack");
270 * Put return value in frame. On the x86 the syscall is
271 * just another trap and the return value from syscall is
272 * ignored. On other machines the return value is put into
273 * the results register by caller of syscall.
277 if(up->procctl == Proc_tracesyscall){
278 stopns = todget(nil);
279 sysretfmt(scallnr, (va_list)(sp+BY2WD), ret, startns, stopns);
281 up->procctl = Proc_stopme;
285 free(up->syscalltrace);
286 up->syscalltrace = nil;
293 noted(ureg, *(ulong*)(sp+BY2WD));
296 if(scallnr != RFORK && (up->procctl || up->nnote))
299 l1cache->wb(); /* system is more stable with this */
301 /* if we delayed sched because we held a lock, sched now */
310 execregs(uintptr entry, ulong ssize, ulong nargs)
315 sp = (ulong*)(USTKTOP - ssize);
319 // memset(ureg, 0, 15*sizeof(ulong));
320 ureg->r13 = (ulong)sp;
322 //print("%lud: EXECREGS pc %#ux sp %#ux nargs %ld\n", up->pid, ureg->pc, ureg->r13, nargs);
323 allcache->wbse(ureg, sizeof *ureg); /* is this needed? */
326 * return the address of kernel/user shared data
329 return USTKTOP-sizeof(Tos);
333 sysprocsetup(Proc* p)
339 * Craft a return frame which will cause the child to pop out of
340 * the scheduler in user mode with the return register zero. Set
341 * pc to point to a l.s return function.
344 forkchild(Proc *p, Ureg *ureg)
348 p->sched.sp = (ulong)p->kstack+KSTACK-sizeof(Ureg);
349 p->sched.pc = (ulong)forkret;
351 cureg = (Ureg*)(p->sched.sp);
352 memmove(cureg, ureg, sizeof(Ureg));
354 /* syscall returns 0 for child */
357 /* Things from bottom of syscall which were never executed */