]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/kw/syscall.c
kernel: apply uintptr for ulong when a pointer is stored
[plan9front.git] / sys / src / 9 / kw / syscall.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../port/error.h"
7 #include "../port/systab.h"
8
9 #include <tos.h>
10 #include "ureg.h"
11
12 #include "arm.h"
13
14 typedef struct {
15         uintptr ip;
16         Ureg*   arg0;
17         char*   arg1;
18         char    msg[ERRMAX];
19         Ureg*   old;
20         Ureg    ureg;
21 } NFrame;
22
23 /*
24  *   Return user to state before notify()
25  */
26 static void
27 noted(Ureg* cur, uintptr arg0)
28 {
29         NFrame *nf;
30         Ureg *nur;
31
32         qlock(&up->debug);
33         if(arg0 != NRSTR && !up->notified){
34                 qunlock(&up->debug);
35                 pprint("call to noted() when not notified\n");
36                 pexit("Suicide", 0);
37         }
38         up->notified = 0;
39         fpunoted();
40
41         nf = up->ureg;
42
43         /* sanity clause */
44         if(!okaddr(PTR2UINT(nf), sizeof(NFrame), 0)){
45                 qunlock(&up->debug);
46                 pprint("bad ureg in noted %#p\n", nf);
47                 pexit("Suicide", 0);
48         }
49
50         /* don't let user change system flags */
51         nur = &nf->ureg;
52         nur->psr &= PsrMask|PsrDfiq|PsrDirq;
53         nur->psr |= (cur->psr & ~(PsrMask|PsrDfiq|PsrDirq));
54
55         memmove(cur, nur, sizeof(Ureg));
56
57         switch((int)arg0){
58         case NCONT:
59         case NRSTR:
60                 if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->sp, BY2WD, 0)){
61                         qunlock(&up->debug);
62                         pprint("suicide: trap in noted\n");
63                         pexit("Suicide", 0);
64                 }
65                 up->ureg = nf->old;
66                 qunlock(&up->debug);
67                 break;
68         case NSAVE:
69                 if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->sp, BY2WD, 0)){
70                         qunlock(&up->debug);
71                         pprint("suicide: trap in noted\n");
72                         pexit("Suicide", 0);
73                 }
74                 qunlock(&up->debug);
75
76                 splhi();
77                 nf->arg1 = nf->msg;
78                 nf->arg0 = &nf->ureg;
79                 nf->ip = 0;
80                 cur->sp = PTR2UINT(nf);
81                 break;
82         default:
83                 up->lastnote.flag = NDebug;
84                 /*FALLTHROUGH*/
85         case NDFLT:
86                 qunlock(&up->debug);
87                 if(up->lastnote.flag == NDebug)
88                         pprint("suicide: %s\n", up->lastnote.msg);
89                 pexit(up->lastnote.msg, up->lastnote.flag != NDebug);
90         }
91 }
92
93 /*
94  *  Call user, if necessary, with note.
95  *  Pass user the Ureg struct and the note on his stack.
96  */
97 int
98 notify(Ureg* ureg)
99 {
100         int l;
101         Note *n;
102         u32int s;
103         uintptr sp;
104         NFrame *nf;
105
106         if(up->procctl)
107                 procctl(up);
108         if(up->nnote == 0)
109                 return 0;
110
111         fpunotify(ureg);
112
113         s = spllo();
114         qlock(&up->debug);
115
116         up->notepending = 0;
117         n = &up->note[0];
118         if(strncmp(n->msg, "sys:", 4) == 0){
119                 l = strlen(n->msg);
120                 if(l > ERRMAX-23)       /* " pc=0x0123456789abcdef\0" */
121                         l = ERRMAX-23;
122                 snprint(n->msg + l, sizeof n->msg - l, " pc=%#lux", ureg->pc);
123         }
124
125         if(n->flag != NUser && (up->notified || up->notify == 0)){
126                 qunlock(&up->debug);
127                 if(n->flag == NDebug)
128                         pprint("suicide: %s\n", n->msg);
129                 pexit(n->msg, n->flag != NDebug);
130         }
131
132         if(up->notified){
133                 qunlock(&up->debug);
134                 splhi();
135                 return 0;
136         }
137                 
138         if(up->notify == nil){
139                 qunlock(&up->debug);
140                 pexit(n->msg, n->flag != NDebug);
141         }
142         if(!okaddr(PTR2UINT(up->notify), 1, 0)){
143                 qunlock(&up->debug);
144                 pprint("suicide: notify function address %#p\n", up->notify);
145                 pexit("Suicide", 0);
146         }
147
148         sp = ureg->sp - sizeof(NFrame);
149         if(!okaddr(sp, sizeof(NFrame), 1)){
150                 qunlock(&up->debug);
151                 pprint("suicide: notify stack address %#p\n", sp);
152                 pexit("Suicide", 0);
153         }
154
155         nf = UINT2PTR(sp);
156         memmove(&nf->ureg, ureg, sizeof(Ureg));
157         nf->old = up->ureg;
158         up->ureg = nf;
159         memmove(nf->msg, up->note[0].msg, ERRMAX);
160         nf->arg1 = nf->msg;
161         nf->arg0 = &nf->ureg;
162         nf->ip = 0;
163
164         ureg->sp = sp;
165         ureg->pc = PTR2UINT(up->notify);
166         up->notified = 1;
167         up->nnote--;
168         memmove(&up->lastnote, &up->note[0], sizeof(Note));
169         memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
170
171         qunlock(&up->debug);
172         splx(s);
173
174         return 1;
175 }
176
177 void
178 syscall(Ureg* ureg)
179 {
180         char *e;
181         u32int s;
182         ulong sp;
183         long ret;
184         int i, scallnr;
185         vlong startns, stopns;
186
187         if(!userureg(ureg))
188                 panic("syscall: from kernel: pc %#lux r14 %#lux psr %#lux",
189                         ureg->pc, ureg->r14, ureg->psr);
190
191         cycles(&up->kentry);
192
193         m->syscall++;
194         up->insyscall = 1;
195         up->pc = ureg->pc;
196         up->dbgreg = ureg;
197
198         scallnr = ureg->r0;
199         up->scallnr = scallnr;
200         spllo();
201         sp = ureg->sp;
202
203         up->nerrlab = 0;
204         ret = -1;
205         if(!waserror()){
206                 if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
207                         validaddr(sp, sizeof(Sargs)+BY2WD, 0);
208                 up->s = *((Sargs*)(sp+BY2WD));
209                 if(up->procctl == Proc_tracesyscall){
210                         syscallfmt(scallnr, ureg->pc, (va_list)up->s.args);
211                         s = splhi();
212                         up->procctl = Proc_stopme;
213                         procctl(up);
214                         splx(s);
215                         startns = todget(nil);
216                 }
217                 if(scallnr >= nsyscall){
218                         pprint("bad sys call number %d pc %#lux\n",
219                                 scallnr, ureg->pc);
220                         postnote(up, 1, "sys: bad sys call", NDebug);
221                         error(Ebadarg);
222                 }
223                 up->psstate = sysctab[scallnr];
224
225         /*      iprint("%s: syscall %s\n", up->text, sysctab[scallnr]?sysctab[scallnr]:"huh?"); */
226
227                 ret = systab[scallnr]((va_list)up->s.args);
228                 poperror();
229         }else{
230                 /* failure: save the error buffer for errstr */
231                 e = up->syserrstr;
232                 up->syserrstr = up->errstr;
233                 up->errstr = e;
234         }
235         if(up->nerrlab){
236                 print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab);
237                 for(i = 0; i < NERR; i++)
238                         print("sp=%#p pc=%#p\n",
239                                 up->errlab[i].sp, up->errlab[i].pc);
240                 panic("error stack");
241         }
242
243         /*
244          *  Put return value in frame.  On the x86 the syscall is
245          *  just another trap and the return value from syscall is
246          *  ignored.  On other machines the return value is put into
247          *  the results register by caller of syscall.
248          */
249         ureg->r0 = ret;
250
251         if(up->procctl == Proc_tracesyscall){
252                 stopns = todget(nil);
253                 sysretfmt(scallnr, (va_list)up->s.args, ret, startns, stopns);
254                 s = splhi();
255                 up->procctl = Proc_stopme;
256                 procctl(up);
257                 splx(s);
258         }
259
260         up->insyscall = 0;
261         up->psstate = 0;
262
263         if(scallnr == NOTED)
264                 noted(ureg, up->s.args[0]);
265
266         splhi();
267         if(scallnr != RFORK && (up->procctl || up->nnote))
268                 notify(ureg);
269
270         /* if we delayed sched because we held a lock, sched now */
271         if(up->delaysched){
272                 sched();
273                 splhi();
274         }
275         kexit(ureg);
276 }
277
278 uintptr
279 execregs(uintptr entry, ulong ssize, ulong nargs)
280 {
281         ulong *sp;
282         Ureg *ureg;
283
284         sp = (ulong*)(USTKTOP - ssize);
285         *--sp = nargs;
286
287         ureg = up->dbgreg;
288 //      memset(ureg, 0, 15*sizeof(ulong));
289         ureg->r13 = (ulong)sp;
290         ureg->pc = entry;
291 //print("%lud: EXECREGS pc %#ux sp %#ux nargs %ld\n", up->pid, ureg->pc, ureg->r13, nargs);
292
293         /*
294          * return the address of kernel/user shared data
295          * (e.g. clock stuff)
296          */
297         return USTKTOP-sizeof(Tos);
298 }
299
300 void
301 sysprocsetup(Proc* p)
302 {
303         fpusysprocsetup(p);
304 }
305
306 /* 
307  *  Craft a return frame which will cause the child to pop out of
308  *  the scheduler in user mode with the return register zero.  Set
309  *  pc to point to a l.s return function.
310  */
311 void
312 forkchild(Proc *p, Ureg *ureg)
313 {
314         Ureg *cureg;
315
316 //print("%lud setting up for forking child %lud\n", up->pid, p->pid);
317         p->sched.sp = (ulong)p->kstack+KSTACK-sizeof(Ureg);
318         p->sched.pc = (ulong)forkret;
319
320         cureg = (Ureg*)(p->sched.sp);
321         memmove(cureg, ureg, sizeof(Ureg));
322
323         /* syscall returns 0 for child */
324         cureg->r0 = 0;
325
326         /* Things from bottom of syscall which were never executed */
327         p->psstate = 0;
328         p->insyscall = 0;
329 }